Below is the list of changes that have just been committed into a local
5.1 repository of andrey. When andrey does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet
1.2186 06/05/25 11:31:28 andrey@lmy004. +9 -0
manual merge
sql/sql_show.cc
1.338 06/05/25 11:31:14 andrey@lmy004. +4 -13
manual merge
mysql-test/r/events.result
1.35 06/05/25 11:31:14 andrey@lmy004. +4 -8
manual merge
sql/sql_parse.cc
1.552 06/05/25 11:31:13 andrey@lmy004. +5 -6
manual merge
sql/event.h
1.29 06/05/25 11:31:13 andrey@lmy004. +0 -0
manual merge
sql/event.cc
1.41 06/05/25 11:31:13 andrey@lmy004. +11 -29
manual merge
mysql-test/t/events.test
1.30 06/05/25 11:31:13 andrey@lmy004. +3 -8
manual merge
sql/event_timed.cc
1.53 06/05/25 10:40:43 andrey@lmy004. +0 -0
Auto merged
sql/event_priv.h
1.22 06/05/25 10:40:43 andrey@lmy004. +0 -0
Auto merged
mysql-test/t/events_bugs.test
1.8 06/05/25 10:40:43 andrey@lmy004. +0 -5
Auto merged
mysql-test/r/events.result
1.34 06/05/25 10:40:42 andrey@lmy004. +0 -0
Change mode to -rw-rw-r--
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: andrey
# Host: lmy004.
# Root: /work/mysql-5.1-release-17394/RESYNC
--- 1.551/sql/sql_parse.cc 2006-05-24 14:33:37 +02:00
+++ 1.552/sql/sql_parse.cc 2006-05-25 11:31:13 +02:00
@@ -3837,16 +3837,16 @@ end_with_restore_list:
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
res= Events::create_event(thd, lex->et,
- (uint) lex->create_info.options,
- &rows_affected);
+ (uint) lex->create_info.options,
+ &rows_affected);
break;
case SQLCOM_ALTER_EVENT:
res= Events::update_event(thd, lex->et, lex->spname,
- &rows_affected);
+ &rows_affected);
break;
case SQLCOM_DROP_EVENT:
res= Events::drop_event(thd, lex->et, lex->drop_if_exists,
- &rows_affected);
+ &rows_affected);
default:;
}
DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
@@ -3884,7 +3884,7 @@ end_with_restore_list:
my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
goto error;
}
- res= Events::show_create_event(thd, lex->spname, lex->et->definer);
+ res= Events::show_create_event(thd, lex->spname);
break;
}
#ifndef DBUG_OFF
--- 1.337/sql/sql_show.cc 2006-05-22 21:54:53 +02:00
+++ 1.338/sql/sql_show.cc 2006-05-25 11:31:14 +02:00
@@ -4020,8 +4020,24 @@ static interval_type get_real_interval_t
extern LEX_STRING interval_type_to_name[];
+
+/*
+ Loads an event from mysql.event and copies it's data to a row of
+ I_S.EVENTS
+
+ Synopsis
+ copy_event_to_schema_table()
+ thd Thread
+ sch_table The schema table (information_schema.event)
+ event_table The event table to use for loading (mysql.event).
+
+ Returns
+ 0 OK
+ 1 Error
+*/
+
static int
-fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
+copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
{
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
CHARSET_INFO *scs= system_charset_info;
@@ -4039,9 +4055,19 @@ fill_events_copy_to_schema_table(THD *th
if (!(!wild || !wild[0] || !wild_compare(et.name.str, wild, 0)))
DBUG_RETURN(0);
-
+
+ /*
+ Skip events in schemas one does not have access to. The check is
+ optimized. It's guaranteed in case of SHOW EVENTS that the user
+ has access.
+ */
+ if (thd->lex->orig_sql_command != SQLCOM_SHOW_EVENTS &&
+ check_access(thd, EVENT_ACL, et.dbname.str, 0, 0, 1,
+ is_schema_db(et.dbname.str)))
+ DBUG_RETURN(0);
+
/* ->field[0] is EVENT_CATALOG and is by default NULL */
-
+
sch_table->field[1]->store(et.dbname.str, et.dbname.length, scs);
sch_table->field[2]->store(et.name.str, et.name.length, scs);
sch_table->field[3]->store(et.definer.str, et.definer.length, scs);
@@ -4053,19 +4079,18 @@ fill_events_copy_to_schema_table(THD *th
ulong sql_mode_len=0;
sql_mode_str=
sys_var_thd_sql_mode::symbolic_mode_representation(thd, et.sql_mode,
- &sql_mode_len);
+ &sql_mode_len);
sch_table->field[9]->store((const char*)sql_mode_str, sql_mode_len, scs);
}
-
+
if (et.expression)
{
String show_str;
/* type */
sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs);
- if (Events::reconstruct_interval_expression(&show_str,
- et.interval,
- et.expression))
+ if (Events::reconstruct_interval_expression(&show_str, et.interval,
+ et.expression))
DBUG_RETURN(1);
sch_table->field[7]->set_notnull();
@@ -4075,7 +4100,7 @@ fill_events_copy_to_schema_table(THD *th
sch_table->field[8]->set_notnull();
sch_table->field[8]->store(ival->str, ival->length, scs);
- //starts & ends
+ /* starts & ends */
sch_table->field[10]->set_notnull();
sch_table->field[10]->store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME);
@@ -4094,13 +4119,13 @@ fill_events_copy_to_schema_table(THD *th
sch_table->field[6]->store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME);
}
- //status
+ /* status */
if (et.status == Event_timed::ENABLED)
sch_table->field[12]->store(STRING_WITH_LEN("ENABLED"), scs);
else
sch_table->field[12]->store(STRING_WITH_LEN("DISABLED"), scs);
- //on_completion
+ /* on_completion */
if (et.on_completion == Event_timed::ON_COMPLETION_DROP)
sch_table->field[13]->store(STRING_WITH_LEN("NOT PRESERVE"), scs);
else
@@ -4130,98 +4155,179 @@ fill_events_copy_to_schema_table(THD *th
}
-int fill_schema_events(THD *thd, TABLE_LIST *tables, COND *cond)
+/*
+ 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)
{
- TABLE *table= tables->table;
- CHARSET_INFO *scs= system_charset_info;
- TABLE *event_table= NULL;
- Open_tables_state backup;
int ret=0;
- bool verbose= false;
- char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
- bool use_prefix_scanning= true;
- uint key_len= 0;
+ CHARSET_INFO *scs= system_charset_info;
+ KEY *key_info;
+ uint key_len;
byte *key_buf= NULL;
LINT_INIT(key_buf);
- DBUG_ENTER("fill_schema_events");
-
- strxmov(definer, thd->security_ctx->priv_user,"@",thd->security_ctx->priv_host,
- NullS);
-
- DBUG_PRINT("info",("db=%s current_user=%s", thd->lex->select_lex.db, definer));
+ DBUG_ENTER("schema_events_do_index_scan");
- thd->reset_n_backup_open_tables_state(&backup);
+ DBUG_PRINT("info", ("Using prefix scanning on PK"));
+ event_table->file->ha_index_init(0, 1);
+ event_table->field[EVEX_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 ((ret= Events::open_event_table(thd, TL_READ, &event_table)))
+ if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
{
- sql_print_error("Table mysql.event is damaged.");
ret= 1;
- goto err;
- }
-
- event_table->file->ha_index_init(0, 1);
-
- /* see others' events only if you have PROCESS_ACL !! */
- verbose= ((thd->lex->verbose ||
- thd->lex->orig_sql_command != SQLCOM_SHOW_EVENTS) &&
- (thd->security_ctx->master_access & PROCESS_ACL));
-
- if (verbose && thd->security_ctx->user)
- {
- ret= event_table->file->index_first(event_table->record[0]);
- use_prefix_scanning= false;
+ /* don't send error, it would be done by sql_alloc_error_handler() */
}
else
{
- event_table->field[Events::FIELD_DEFINER]->
- store(definer, strlen(definer), scs);
- key_len= event_table->key_info->key_part[0].store_length;
-
- if (thd->lex->select_lex.db)
- {
- event_table->field[Events::FIELD_DB]->
- store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs);
- key_len+= event_table->key_info->key_part[1].store_length;
- }
- if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
+ 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)))
{
- ret= 1;
- goto err;
+ 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);
}
-
- key_copy(key_buf, event_table->record[0], event_table->key_info, key_len);
- ret= event_table->file->index_read(event_table->record[0], key_buf, key_len,
- HA_READ_PREFIX);
+ 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);
+}
+
- if (ret)
+/*
+ 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= (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND) ? 0 : 1;
- goto err;
+ 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);
- while (!ret)
- {
- if ((ret= fill_events_copy_to_schema_table(thd, table, event_table)))
- goto err;
+ 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;
- if (use_prefix_scanning)
- ret= event_table->file->
- index_next_same(event_table->record[0], key_buf, key_len);
- else
- ret= event_table->file->index_next(event_table->record[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->orig_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);
}
- // ret is guaranteed to be != 0
- ret= (ret != HA_ERR_END_OF_FILE);
-err:
- if (event_table)
+
+ 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))
{
- event_table->file->ha_index_end();
- close_thread_tables(thd);
+ 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->orig_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);
}
--- 1.33/mysql-test/r/events.result 2006-05-16 14:13:38 +02:00
+++ 1.35/mysql-test/r/events.result 2006-05-25 11:31:14 +02:00
@@ -17,13 +17,13 @@ db_x
SHOW TABLES FROM db_x;
Tables_in_db_x
x_table
-SET GLOBAL event_scheduler=0;
+SET GLOBAL event_scheduler=2;
DROP EVENT e_x1;
DROP EVENT e_x2;
DROP DATABASE db_x;
DROP USER pauline@localhost;
USE events_test;
-SET GLOBAL event_scheduler=0;
+SET GLOBAL event_scheduler=2;
drop event if exists event1;
Warnings:
Note 1305 Event event1 does not exist
@@ -100,7 +100,7 @@ a
800219
drop event non_qualif_ev;
drop table non_qualif;
-set global event_scheduler = 0;
+set global event_scheduler = 2;
create table t_event3 (a int, b float);
drop event if exists event3;
Warnings:
@@ -185,10 +185,10 @@ SHOW CREATE EVENT root20;
Event sql_mode Create Event
root20 CREATE EVENT `root20` ON SCHEDULE EVERY '50 20:12:45' DAY_SECOND ON COMPLETION NOT PRESERVE ENABLE DO select 1
set names cp1251;
+create event ðóóò21 on schedule every '50:23:59:95' day_second COMMENT 'òîâà å 1251 êîìåíòàð' do select 1;
+SHOW CREATE EVENT ðóóò21;
Event sql_mode Create Event
+ðóóò21 CREATE EVENT `ðóóò21` ON SCHEDULE EVERY '51 0:0:35' DAY_SECOND ON COMPLETION NOT PRESERVE ENABLE COMMENT 'òîâà å 1251 êîìåíòàð' DO select 1
insert into mysql.event (db, name, body, definer, interval_value, interval_field) values (database(), "root22", "select 1", user(), 100, "SECOND_MICROSECOND");
show create event root22;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
@@ -213,7 +213,7 @@ drop event root17_1;
drop event root18;
drop event root19;
drop event root20;
+drop event ðóóò21;
set names latin1;
CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing";
SHOW EVENTS;
@@ -293,12 +293,12 @@ ERROR HY000: Incorrect AT value: 'defini
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=0;
+set event_scheduler=2;
ERROR HY000: Variable 'event_scheduler' is a GLOBAL variable and should be set with SET GLOBAL
-set global event_scheduler=2;
-ERROR 42000: Variable 'event_scheduler' can't be set to the value of '2'
+set global event_scheduler=3;
+ERROR 42000: Variable 'event_scheduler' can't be set to the value of '3'
"DISABLE the scheduler. Testing that it does not work when the variable is 0"
-set global event_scheduler=0;
+set global event_scheduler=2;
select definer, name, db from mysql.event;
definer name db
select get_lock("test_lock1", 20);
@@ -309,9 +309,10 @@ create event закачка on schedule
select definer, name, db from mysql.event;
definer name db
root@localhost закачка events_test
-"Should be 0 processes"
+"Should be only 1 process"
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
+event_scheduler localhost NULL Connect Suspended NULL
select release_lock("test_lock1");
release_lock("test_lock1")
1
@@ -329,11 +330,12 @@ get_lock("test_lock2", 20)
create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20);
"Let some time pass to the event starts"
"Should have only 2 processes: the scheduler and the locked event"
-select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping 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."
select release_lock("test_lock2");
release_lock("test_lock2")
1
@@ -343,21 +345,17 @@ select get_lock("test_lock2_1", 20);
get_lock("test_lock2_1", 20)
1
create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20);
-"Should see 1 process, locked on get_lock("
-"Shutting down the scheduler, it should wait for the running event"
-set global event_scheduler=0;
-"Should have only 2 processes: the scheduler and the locked event"
-select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+"Should have only 3 processes: the scheduler, our conn and the locked event"
+select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
-"Release the lock so the child process should finish. Hence the scheduler also"
-select release_lock("test_lock2_1");
-release_lock("test_lock2_1")
-1
-"Should see 0 processes now:"
-select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+set global event_scheduler=2;
+"Should have only our process now:"
+select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
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;
@@ -374,6 +372,9 @@ events_test white_space root@localhost s
drop event white_space;
create event white_space on schedule every 10 hour disable do
select 2;
+select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space';
+event_schema event_name definer event_body
+events_test white_space root@localhost select 2
select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space';
event_schema event_name definer event_body
events_test white_space root@localhost select 2
--- 1.29/mysql-test/t/events.test 2006-05-16 14:13:38 +02:00
+++ 1.30/mysql-test/t/events.test 2006-05-25 11:31:13 +02:00
@@ -15,11 +15,10 @@ CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SE
connection default;
SHOW DATABASES LIKE 'db_x';
SET GLOBAL event_scheduler=1;
---sleep 2
+--sleep 1.5
SHOW DATABASES LIKE 'db_x';
SHOW TABLES FROM db_x;
-SET GLOBAL event_scheduler=0;
---sleep 1
+SET GLOBAL event_scheduler=2;
connection priv_conn;
DROP EVENT e_x1;
DROP EVENT e_x2;
@@ -31,8 +30,7 @@ USE events_test;
#
# END: BUG #17289 Events: missing privilege check for drop database
#
-SET GLOBAL event_scheduler=0;
---sleep 1
+SET GLOBAL event_scheduler=2;
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;
@@ -92,11 +90,11 @@ drop event e_43;
--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 2
+--sleep 1
select * from non_qualif;
drop event non_qualif_ev;
drop table non_qualif;
-set global event_scheduler = 0;
+set global event_scheduler = 2;
create table t_event3 (a int, b float);
drop event if exists event3;
@@ -147,8 +145,8 @@ SHOW CREATE EVENT root19;
create event root20 on schedule every '50:20:12:45' day_second do select 1;
SHOW CREATE EVENT root20;
set names cp1251;
+create event ðóóò21 on schedule every '50:23:59:95' day_second COMMENT 'òîâà å 1251 êîìåíòàð' do select 1;
+SHOW CREATE EVENT ðóóò21;
insert into mysql.event (db, name, body, definer, interval_value, interval_field) values (database(), "root22", "select 1", user(), 100, "SECOND_MICROSECOND");
--error 1235
show create event root22;
@@ -173,7 +171,7 @@ drop event root17_1;
drop event root18;
drop event root19;
drop event root20;
+drop event ðóóò21;
set names latin1;
#
@@ -256,21 +254,21 @@ create event задачка on schedule
drop event задачка;
# event_scheduler is a global var
---error 1229
-set event_scheduler=0;
-# event_scheduler could be only either 0 or 1
---error 1231
-set global event_scheduler=2;
+--error ER_GLOBAL_VARIABLE
+set event_scheduler=2;
+# event_scheduler could be only either 1 or 2
+--error ER_WRONG_VALUE_FOR_VAR
+set global event_scheduler=3;
--echo "DISABLE the scheduler. Testing that it does not work when the variable is 0"
-set global event_scheduler=0;
+set global event_scheduler=2;
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);
--echo "Should return 1 row"
select definer, name, db from mysql.event;
---echo "Should be 0 processes"
+--echo "Should be only 1 process"
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock("test_lock1");
drop event закачка;
@@ -288,7 +286,7 @@ create event закачка on schedule
--echo "Let some time pass to the event starts"
--sleep 2
--echo "Should have only 2 processes: the scheduler and the locked event"
-select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;--echo "Release the mutex, the event worker should finish."
--echo "Release the mutex, the event worker should finish."
select release_lock("test_lock2");
drop event закачка;
@@ -305,18 +303,11 @@ set global event_scheduler=1;
select get_lock("test_lock2_1", 20);
create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20);
--sleep 1
---echo "Should see 1 process, locked on get_lock("
-#select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
---echo "Shutting down the scheduler, it should wait for the running event"
-set global event_scheduler=0;
---sleep 1
---echo "Should have only 2 processes: the scheduler and the locked event"
+--echo "Should have only 3 processes: the scheduler, our conn and the locked event"
+select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+set global event_scheduler=2;
+--echo "Should have only our process now:"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
---echo "Release the lock so the child process should finish. Hence the scheduler also"
-select release_lock("test_lock2_1");
---sleep 1
---echo "Should see 0 processes now:"
-select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
drop event закачка21;
####
@@ -352,7 +343,7 @@ drop event white_space;
# END: BUG #17453: Creating Event crash the server
#
-##set global event_scheduler=1;
+#
# Bug#17403 "Events: packets out of order with show create event"
#
create event e1 on schedule every 1 year do set @a = 5;
@@ -366,7 +357,7 @@ drop event e1;
##select get_lock("test_lock3", 20);
##create event закачка on schedule every 10 hour do select get_lock("test_lock3", 20);
##select sleep(2);
-##show processlist;
+##select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
##drop event закачка;
##select release_lock("test_lock3");
@@ -376,14 +367,14 @@ drop event e1;
##select get_lock("test_lock4", 20);
##create event закачка4 on schedule every 1 second do select get_lock("test_lock4", 20);
##select sleep(3);
-##--replace_column 1 # 6 #
+##select /*6*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
##drop event закачка4;
##select release_lock("test_lock4");
-##set global event_scheduler=0;
+##set global event_scheduler=2;
##select sleep(2);
##--replace_column 1 # 6 #
+##show processlist;
##select count(*) from mysql.event;
drop database events_test;
-
--- 1.7/mysql-test/t/events_bugs.test 2006-05-16 14:13:38 +02:00
+++ 1.8/mysql-test/t/events_bugs.test 2006-05-25 10:40:43 +02:00
@@ -60,7 +60,7 @@ create event e_55 on schedule every 10 m
#
# Start - 16407: Events: Changes in sql_mode won't be taken into account
#
-set global event_scheduler=0;
+set global event_scheduler=2;
--echo "Wait a bit to settle down"
--sleep 1
delete from mysql.event;
@@ -79,7 +79,7 @@ delimiter ;|
--echo "Now if everything is fine the event has compiled and is locked
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('test_bug16407');
-set global event_scheduler= 0;
+set global event_scheduler= 2;
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
--echo "Let's check whether we change the sql_mode on ALTER EVENT"
set sql_mode='traditional';
@@ -121,9 +121,9 @@ set global event_scheduler= 1;
--sleep 1
select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('ee_16407_2');
---sleep 3
+--sleep 2
select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
-set global event_scheduler= 0;
+set global event_scheduler= 2;
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;
@@ -156,7 +156,7 @@ set global event_scheduler= 1;
--echo "Should have 2 locked processes"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('ee_16407_5');
---sleep 3
+--sleep 2
--echo "Should have 0 processes locked"
select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select * from events_smode_test order by ev_name, a;
@@ -166,7 +166,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= 0;
+set global event_scheduler= 2;
drop table events_smode_test;
set sql_mode=@old_sql_mode;
#
--- 1.40/sql/event.cc 2006-05-16 14:13:38 +02:00
+++ 1.41/sql/event.cc 2006-05-25 11:31:13 +02:00
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2005 MySQL AB
+/* 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
@@ -16,13 +16,12 @@
#include "event_priv.h"
#include "event.h"
+#include "event_scheduler.h"
#include "sp.h"
+#include "sp_head.h"
/*
TODO list :
- - The default value of created/modified should not be 0000-00-00 because of
- STRICT mode restricions.
-
- CREATE EVENT should not go into binary log! Does it now? The SQL statements
issued by the EVENT are replicated.
I have an idea how to solve the problem at failover. So the status field
@@ -38,23 +37,8 @@
ENABLED to DISABLED status change and this is safe for replicating. As well
an event may be deleted which is also safe for RBR.
- - Maybe move all allocations during parsing to evex_mem_root thus saving
- double parsing in evex_create_event!
-
- - If the server is killed (stopping) try to kill executing events?
-
- - What happens if one renames an event in the DB while it is in memory?
- Or even deleting it?
-
- - Consider using conditional variable when doing shutdown instead of
- waiting till all worker threads end.
-
- - Make Event_timed::get_show_create_event() work
-
- Add logging to file
- - Move comparison code to class Event_timed
-
Warning:
- For now parallel execution is not possible because the same sp_head cannot be
executed few times!!! There is still no lock attached to particular event.
@@ -62,12 +46,26 @@ Warning:
*/
-QUEUE EVEX_EQ_NAME;
MEM_ROOT evex_mem_root;
time_t mysql_event_last_create_time= 0L;
-static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = {
+const char *event_scheduler_state_names[]=
+ { "OFF", "0", "ON", "1", "SUSPEND", "2", NullS };
+
+TYPELIB Events::opt_typelib=
+{
+ array_elements(event_scheduler_state_names)-1,
+ "",
+ event_scheduler_state_names,
+ NULL
+};
+
+
+ulong Events::opt_event_scheduler= 2;
+
+static
+TABLE_FIELD_W_TYPE event_table_fields[Events::FIELD_COUNT] = {
{
{(char *) STRING_WITH_LEN("db")},
{(char *) STRING_WITH_LEN("char(64)")},
@@ -186,41 +184,17 @@ LEX_STRING interval_type_to_name[] = {
};
-
-/*
- Inits the scheduler queue - prioritized queue from mysys/queue.c
-
- Synopsis
- evex_queue_init()
-
- queue - pointer the the memory to be initialized as queue. has to be
- allocated from the caller
-
- Notes
- During initialization the queue is sized for 30 events, and when is full
- will auto extent with 30.
-*/
-
-void
-evex_queue_init(EVEX_QUEUE_TYPE *queue)
-{
- if (init_queue_ex(queue, 30 /*num_el*/, 0 /*offset*/, 0 /*smallest_on_top*/,
- event_timed_compare_q, NULL, 30 /*auto_extent*/))
- sql_print_error("Insufficient memory to initialize executing queue.");
-}
-
-
/*
Compares 2 LEX strings regarding case.
- Synopsis
+ SYNOPSIS
my_time_compare()
s - first LEX_STRING
t - second LEX_STRING
cs - charset
- RETURNS:
+ RETURN VALUE
-1 - s < t
0 - s == t
1 - s > t
@@ -239,32 +213,26 @@ int sortcmp_lex_string(LEX_STRING s, LEX
/*
Compares 2 TIME structures
- Synopsis
+ SYNOPSIS
my_time_compare()
a - first TIME
b - second time
- RETURNS:
+ RETURN VALUE
-1 - a < b
0 - a == b
1 - a > b
- Notes
+ NOTES
TIME.second_part is not considered during comparison
*/
int
my_time_compare(TIME *a, TIME *b)
{
-
-#ifdef ENABLE_WHEN_WE_HAVE_MILLISECOND_IN_TIMESTAMPS
- my_ulonglong a_t= TIME_to_ulonglong_datetime(a)*100L + a->second_part;
- my_ulonglong b_t= TIME_to_ulonglong_datetime(b)*100L + b->second_part;
-#else
my_ulonglong a_t= TIME_to_ulonglong_datetime(a);
my_ulonglong b_t= TIME_to_ulonglong_datetime(b);
-#endif
if (a_t > b_t)
return 1;
@@ -276,36 +244,11 @@ my_time_compare(TIME *a, TIME *b)
/*
- Compares the execute_at members of 2 Event_timed instances
-
- Synopsis
- event_timed_compare()
-
- a - first Event_timed object
- b - second Event_timed object
-
- RETURNS:
- -1 - a->execute_at < b->execute_at
- 0 - a->execute_at == b->execute_at
- 1 - a->execute_at > b->execute_at
-
- Notes
- execute_at.second_part is not considered during comparison
-*/
-
-int
-event_timed_compare(Event_timed *a, Event_timed *b)
-{
- return my_time_compare(&a->execute_at, &b->execute_at);
-}
-
-
-/*
Compares the execute_at members of 2 Event_timed instances.
Used as callback for the prioritized queue when shifting
elements inside.
- Synopsis
+ SYNOPSIS
event_timed_compare()
vptr - not used (set it to NULL)
@@ -324,7 +267,8 @@ event_timed_compare(Event_timed *a, Even
int
event_timed_compare_q(void *vptr, byte* a, byte *b)
{
- return event_timed_compare((Event_timed *)a, (Event_timed *)b);
+ return my_time_compare(&((Event_timed *)a)->execute_at,
+ &((Event_timed *)b)->execute_at);
}
@@ -335,8 +279,8 @@ event_timed_compare_q(void *vptr, byte*
YEAR_MONTH - expression is in months
DAY_MINUTE - expression is in minutes
- Synopsis
- event_reconstruct_interval_expression()
+ SYNOPSIS
+ Events::reconstruct_interval_expression()
buf - preallocated String buffer to add the value to
interval - the interval type (for instance YEAR_MONTH)
expression - the value in the lowest entity
@@ -347,9 +291,9 @@ event_timed_compare_q(void *vptr, byte*
*/
int
-event_reconstruct_interval_expression(String *buf,
- interval_type interval,
- longlong expression)
+Events::reconstruct_interval_expression(String *buf,
+ interval_type interval,
+ longlong expression)
{
ulonglong expr= expression;
char tmp_buff[128], *end;
@@ -466,19 +410,20 @@ common_1_lev_code:
Open mysql.event table for read
SYNOPSIS
- evex_open_event_table_for_read()
+ Events::open_event_table()
thd Thread context
lock_type How to lock the table
table The table pointer
- RETURN
+ RETURN VALUE
1 Cannot lock table
2 The table is corrupted - different number of fields
0 OK
*/
int
-evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table)
+Events::open_event_table(THD *thd, enum thr_lock_type lock_type,
+ TABLE **table)
{
TABLE_LIST tables;
DBUG_ENTER("open_proc_table");
@@ -491,7 +436,8 @@ evex_open_event_table(THD *thd, enum thr
if (simple_open_n_lock_tables(thd, &tables))
DBUG_RETURN(1);
- if (table_check_intact(tables.table, EVEX_FIELD_COUNT, event_table_fields,
+ if (table_check_intact(tables.table, Events::FIELD_COUNT,
+ event_table_fields,
&mysql_event_last_create_time,
ER_CANNOT_LOAD_FROM_TABLE))
{
@@ -561,43 +507,46 @@ evex_db_find_event_by_name(THD *thd, con
DBUG_RETURN(EVEX_KEY_NOT_FOUND);
- table->field[EVEX_FIELD_DB]->store(dbname.str, dbname.length, &my_charset_bin);
- table->field[EVEX_FIELD_NAME]->store(ev_name.str, ev_name.length,
- &my_charset_bin);
+ table->field[Events::FIELD_DB]->store(dbname.str, dbname.length,
+ &my_charset_bin);
+ table->field[Events::FIELD_NAME]->store(ev_name.str, ev_name.length,
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 fonud"));
DBUG_RETURN(EVEX_KEY_NOT_FOUND);
+ }
+ DBUG_PRINT("info", ("Row found!"));
DBUG_RETURN(0);
}
/*
- Puts some data common to CREATE and ALTER EVENT into a row.
+ Puts some data common to CREATE and ALTER EVENT into a row.
- SYNOPSIS
- evex_fill_row()
- thd THD
- table the row to fill out
- et Event's data
-
- Returns
- 0 - ok
- EVEX_GENERAL_ERROR - bad data
- EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
+ SYNOPSIS
+ evex_fill_row()
+ thd THD
+ table the row to fill out
+ et Event's data
- DESCRIPTION
- Used both when an event is created and when it is altered.
+ 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
evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
{
- CHARSET_INFO *scs= system_charset_info;
- enum evex_table_field field_num;
+ enum Events::enum_table_field field_num;
DBUG_ENTER("evex_fill_row");
@@ -605,23 +554,19 @@ evex_fill_row(THD *thd, TABLE *table, Ev
DBUG_PRINT("info", ("name =[%s]", et->name.str));
DBUG_PRINT("info", ("body =[%s]", et->body.str));
- if (table->field[field_num= EVEX_FIELD_DEFINER]->
- store(et->definer.str, et->definer.length, scs))
+ if (table->field[field_num= Events::FIELD_DB]->
+ store(et->dbname.str, et->dbname.length, system_charset_info))
goto err_truncate;
- if (table->field[field_num= EVEX_FIELD_DB]->
- store(et->dbname.str, et->dbname.length, scs))
+ if (table->field[field_num= Events::FIELD_NAME]->
+ store(et->name.str, et->name.length, system_charset_info))
goto err_truncate;
- if (table->field[field_num= EVEX_FIELD_NAME]->
- store(et->name.str, et->name.length, scs))
- goto err_truncate;
-
- /* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull() */
- table->field[EVEX_FIELD_ON_COMPLETION]->store((longlong)et->on_completion,
- true);
+ /* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/
+ table->field[Events::FIELD_ON_COMPLETION]->
+ store((longlong)et->on_completion, true);
- table->field[EVEX_FIELD_STATUS]->store((longlong)et->status, true);
+ table->field[Events::FIELD_STATUS]->store((longlong)et->status, true);
/*
Change the SQL_MODE only if body was present in an ALTER EVENT and of course
@@ -629,53 +574,54 @@ evex_fill_row(THD *thd, TABLE *table, Ev
*/
if (et->body.str)
{
- table->field[EVEX_FIELD_SQL_MODE]->store((longlong)thd->variables.sql_mode,
- true);
+ table->field[Events::FIELD_SQL_MODE]->
+ store((longlong)thd->variables.sql_mode, true);
- if (table->field[field_num= EVEX_FIELD_BODY]->
- store(et->body.str, et->body.length, scs))
+ if (table->field[field_num= Events::FIELD_BODY]->
+ store(et->body.str, et->body.length, system_charset_info))
goto err_truncate;
}
if (et->expression)
{
- table->field[EVEX_FIELD_INTERVAL_EXPR]->set_notnull();
- table->field[EVEX_FIELD_INTERVAL_EXPR]->store((longlong)et->expression,true);
+ table->field[Events::FIELD_INTERVAL_EXPR]->set_notnull();
+ table->field[Events::FIELD_INTERVAL_EXPR]->
+ store((longlong)et->expression, true);
- table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_notnull();
+ table->field[Events::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!
*/
- table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1,
- true);
+ table->field[Events::FIELD_TRANSIENT_INTERVAL]->
+ store((longlong)et->interval+1, true);
- table->field[EVEX_FIELD_EXECUTE_AT]->set_null();
+ table->field[Events::FIELD_EXECUTE_AT]->set_null();
if (!et->starts_null)
{
- table->field[EVEX_FIELD_STARTS]->set_notnull();
- table->field[EVEX_FIELD_STARTS]->
+ table->field[Events::FIELD_STARTS]->set_notnull();
+ table->field[Events::FIELD_STARTS]->
store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
}
if (!et->ends_null)
{
- table->field[EVEX_FIELD_ENDS]->set_notnull();
- table->field[EVEX_FIELD_ENDS]->
+ table->field[Events::FIELD_ENDS]->set_notnull();
+ table->field[Events::FIELD_ENDS]->
store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
}
}
else if (et->execute_at.year)
{
- table->field[EVEX_FIELD_INTERVAL_EXPR]->set_null();
- table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_null();
- table->field[EVEX_FIELD_STARTS]->set_null();
- table->field[EVEX_FIELD_ENDS]->set_null();
+ table->field[Events::FIELD_INTERVAL_EXPR]->set_null();
+ table->field[Events::FIELD_TRANSIENT_INTERVAL]->set_null();
+ table->field[Events::FIELD_STARTS]->set_null();
+ table->field[Events::FIELD_ENDS]->set_null();
- table->field[EVEX_FIELD_EXECUTE_AT]->set_notnull();
- table->field[EVEX_FIELD_EXECUTE_AT]->store_time(&et->execute_at,
- MYSQL_TIMESTAMP_DATETIME);
+ table->field[Events::FIELD_EXECUTE_AT]->set_notnull();
+ table->field[Events::FIELD_EXECUTE_AT]->
+ store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
}
else
{
@@ -686,13 +632,12 @@ evex_fill_row(THD *thd, TABLE *table, Ev
*/
}
- ((Field_timestamp *)table->field[EVEX_FIELD_MODIFIED])->set_time();
+ ((Field_timestamp *)table->field[Events::FIELD_MODIFIED])->set_time();
if (et->comment.str)
{
- if (table->field[field_num= EVEX_FIELD_COMMENT]->store(et->comment.str,
- et->comment.length,
- scs))
+ if (table->field[field_num= Events::FIELD_COMMENT]->
+ store(et->comment.str, et->comment.length, system_charset_info))
goto err_truncate;
}
@@ -704,28 +649,30 @@ err_truncate:
/*
- Creates an event in mysql.event
+ Creates an event in mysql.event
+
+ SYNOPSIS
+ db_create_event()
+ thd THD
+ et Event_timed object containing information for the event
+ create_if_not If an warning should be generated in case event exists
+ rows_affected How many rows were affected
- SYNOPSIS
- db_create_event()
- thd THD
- et Event_timed object containing information for the event
- create_if_not - if an warning should be generated in case event exists
- rows_affected - how many rows were affected
-
- Return value
- 0 - OK
- EVEX_GENERAL_ERROR - Failure
- DESCRIPTION
- Creates an event. Relies on evex_fill_row which is shared with
- db_update_event. The name of the event is inside "et".
+ RETURN VALUE
+ 0 - OK
+ EVEX_GENERAL_ERROR - Failure
+
+ DESCRIPTION
+ Creates an event. Relies on evex_fill_row which is shared with
+ db_update_event. The name of the event is inside "et".
*/
-static int
+int
db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
uint *rows_affected)
{
int ret= 0;
+ CHARSET_INFO *scs= system_charset_info;
TABLE *table;
char olddb[128];
bool dbchanged= false;
@@ -734,13 +681,13 @@ db_create_event(THD *thd, Event_timed *e
*rows_affected= 0;
DBUG_PRINT("info", ("open mysql.event for update"));
- if (evex_open_event_table(thd, TL_WRITE, &table))
+ if (Events::open_event_table(thd, TL_WRITE, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
goto err;
}
- DBUG_PRINT("info", ("check existence of an event with the same name"));
+ DBUG_PRINT("info", ("check existance of an event with the same name"));
if (!evex_db_find_event_aux(thd, et, table))
{
if (create_if_not)
@@ -778,7 +725,7 @@ db_create_event(THD *thd, Event_timed *e
goto err;
}
- if (et->body.length > table->field[EVEX_FIELD_BODY]->field_length)
+ if (et->body.length > table->field[Events::FIELD_BODY]->field_length)
{
my_error(ER_TOO_LONG_BODY, MYF(0), et->name.str);
goto err;
@@ -791,7 +738,7 @@ db_create_event(THD *thd, Event_timed *e
goto err;
}
- ((Field_timestamp *)table->field[EVEX_FIELD_CREATED])->set_time();
+ ((Field_timestamp *)table->field[Eevents::FIELD_CREATED])->set_time();
/*
evex_fill_row() calls my_error() in case of error so no need to
@@ -811,8 +758,8 @@ db_create_event(THD *thd, Event_timed *e
{
thd->clear_error();
/* Such a statement can always go directly to binlog, no trans cache */
- thd->binlog_query(THD::MYSQL_QUERY_TYPE,
- thd->query, thd->query_length, FALSE, FALSE);
+ thd->binlog_query(THD::MYSQL_QUERY_TYPE, thd->query, thd->query_length,
+ FALSE, FALSE);
}
#endif
@@ -834,17 +781,21 @@ err:
/*
- Used to execute ALTER EVENT. Pendant to evex_update_event().
+ Used to execute ALTER EVENT. Pendant to Events::update_event().
+
+ SYNOPSIS
+ db_update_event()
+ thd THD
+ sp_name the name of the event to alter
+ et event's data
+
+ RETURN VALUE
+ 0 OK
+ EVEX_GENERAL_ERROR Error occured (my_error() called)
- SYNOPSIS
- db_update_event()
- thd THD
- sp_name the name of the event to alter
- et event's data
-
- NOTES
- sp_name is passed since this is the name of the event to
- alter in case of RENAME TO.
+ NOTES
+ sp_name is passed since this is the name of the event to
+ alter in case of RENAME TO.
*/
static int
@@ -860,7 +811,7 @@ db_update_event(THD *thd, Event_timed *e
DBUG_PRINT("enter", ("rename to: %.*s", new_name->m_name.length,
new_name->m_name.str));
- if (evex_open_event_table(thd, TL_WRITE, &table))
+ if (Events::open_event_table(thd, TL_WRITE, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
goto err;
@@ -905,9 +856,9 @@ db_update_event(THD *thd, Event_timed *e
if (new_name)
{
- table->field[EVEX_FIELD_DB]->
+ table->field[Events::FIELD_DB]->
store(new_name->m_db.str, new_name->m_db.length, system_charset_info);
- table->field[EVEX_FIELD_NAME]->
+ table->field[Events::FIELD_NAME]->
store(new_name->m_name.str, new_name->m_name.length, system_charset_info);
}
@@ -929,33 +880,33 @@ err:
/*
- Looks for a named event in mysql.event and in case of success returns
- an object will data loaded from the table.
+ Looks for a named event in mysql.event and in case of success returns
+ an object will data loaded from the table.
- SYNOPSIS
- db_find_event()
- thd THD
- name the name of the event to find
- definer who owns the event
- ett event's data if event is found
- tbl TABLE object to use when not NULL
-
- NOTES
- 1) Use sp_name for look up, return in **ett if found
- 2) tbl is not closed at exit
-
- RETURN
- 0 ok In this case *ett is set to the event
- # error *ett == 0
+ SYNOPSIS
+ db_find_event()
+ thd THD
+ name the name of the event to find
+ definer who owns the event
+ ett event's data if event is found
+ tbl TABLE object to use when not NULL
+
+ NOTES
+ 1) Use sp_name for look up, return in **ett if found
+ 2) tbl is not closed at exit
+
+ RETURN VALUE
+ 0 ok In this case *ett is set to the event
+ # error *ett == 0
*/
-static int
+int
db_find_event(THD *thd, sp_name *name, Event_timed **ett, TABLE *tbl,
MEM_ROOT *root)
{
TABLE *table;
int ret;
- Event_timed *et= 0;
+ Event_timed *et= NULL;
DBUG_ENTER("db_find_event");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
@@ -964,7 +915,7 @@ db_find_event(THD *thd, sp_name *name, E
if (tbl)
table= tbl;
- else if (evex_open_event_table(thd, TL_READ, &table))
+ else if (Events::open_event_table(thd, TL_READ, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
ret= EVEX_GENERAL_ERROR;
@@ -1005,177 +956,43 @@ done:
/*
- Looks for a named event in mysql.event and then loads it from
- the table, compiles it and insert it into the cache.
-
- SYNOPSIS
- evex_load_and_compile_event()
- thd THD
- spn the name of the event to alter
- definer who is the owner
- use_lock whether to obtain a lock on LOCK_event_arrays or not
-
- RETURN VALUE
- 0 - OK
- < 0 - error (in this case underlying functions call my_error()).
-*/
-
-static int
-evex_load_and_compile_event(THD * thd, sp_name *spn, bool use_lock)
-{
- int ret= 0;
- MEM_ROOT *tmp_mem_root;
- Event_timed *ett;
- Open_tables_state backup;
-
- DBUG_ENTER("db_load_and_compile_event");
- DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
-
- tmp_mem_root= thd->mem_root;
- thd->mem_root= &evex_mem_root;
-
- thd->reset_n_backup_open_tables_state(&backup);
- /* no need to use my_error() here because db_find_event() has done it */
- ret= db_find_event(thd, spn, &ett, NULL, NULL);
- thd->restore_backup_open_tables_state(&backup);
- if (ret)
- goto done;
-
- ett->compute_next_execution_time();
- if (use_lock)
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
-
- evex_queue_insert(&EVEX_EQ_NAME, (EVEX_PTOQEL) ett);
-
- /*
- There is a copy in the array which we don't need. sphead won't be
- destroyed.
- */
-
- if (use_lock)
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
-
-done:
- if (thd->mem_root != tmp_mem_root)
- thd->mem_root= tmp_mem_root;
-
- DBUG_RETURN(ret);
-}
-
-
-/*
- Removes from queue in memory the event which is identified by the tupple
- (db, name).
-
- SYNOPSIS
- evex_remove_from_cache()
-
- db - db name
- name - event name
- use_lock - whether to lock the mutex LOCK_event_arrays or not in case it
- has been already locked outside
- is_drop - if an event is currently being executed then we can also delete
- the Event_timed instance, so we alarm the event that it should
- drop itself if this parameter is set to TRUE. It's false on
- ALTER EVENT.
-
- RETURNS
- 0 OK (always)
-*/
-
-static int
-evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
- bool is_drop)
-{
- uint i;
- int ret= 0;
-
- DBUG_ENTER("evex_remove_from_cache");
- /*
- It is possible that 2 (or 1) pass(es) won't find the event in memory.
- The reason is that DISABLED events are not cached.
- */
-
- if (use_lock)
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
-
- for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i)
- {
- Event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, Event_timed*);
- DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?",db->str,name->str, et->dbname.str,
- et->name.str));
- if (!sortcmp_lex_string(*name, et->name, system_charset_info) &&
- !sortcmp_lex_string(*db, et->dbname, system_charset_info))
- {
- if (et->can_spawn_now())
- {
- DBUG_PRINT("evex_remove_from_cache", ("not running - free and delete"));
- et->free_sp();
- delete et;
- }
- else
- {
- DBUG_PRINT("evex_remove_from_cache",
- ("running.defer mem free. is_drop=%d", is_drop));
- et->flags|= EVENT_EXEC_NO_MORE;
- et->dropped= is_drop;
- }
- DBUG_PRINT("evex_remove_from_cache", ("delete from queue"));
- evex_queue_delete_element(&EVEX_EQ_NAME, i);
- /* ok, we have cleaned */
- ret= 0;
- goto done;
- }
- }
-
-done:
- if (use_lock)
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
-
- DBUG_RETURN(ret);
-}
+ The function exported to the world for creating of events.
+ SYNOPSIS
+ Events::create_event()
+ thd THD
+ et event's data
+ create_options Options specified when in the query. We are
+ interested whether there is IF NOT EXISTS
+ rows_affected How many rows were affected
-/*
- The function exported to the world for creating of events.
+ RETURN VALUE
+ 0 OK
+ !0 Error
- SYNOPSIS
- evex_create_event()
- thd THD
- et event's data
- create_options Options specified when in the query. We are
- interested whether there is IF NOT EXISTS
- rows_affected How many rows were affected
-
- NOTES
- - in case there is an event with the same name (db) and
- IF NOT EXISTS is specified, an warning is put into the W stack.
+ NOTES
+ - in case there is an event with the same name (db) and
+ IF NOT EXISTS is specified, an warning is put into the W stack.
*/
int
-evex_create_event(THD *thd, Event_timed *et, uint create_options,
- uint *rows_affected)
+Events::create_event(THD *thd, Event_timed *et, uint create_options,
+ uint *rows_affected)
{
- int ret = 0;
+ int ret;
- DBUG_ENTER("evex_create_event");
+ DBUG_ENTER("Events::create_event");
DBUG_PRINT("enter", ("name: %*s options:%d", et->name.length,
et->name.str, create_options));
- if ((ret = db_create_event(thd, et,
+ if (!(ret = db_create_event(thd, et,
create_options & HA_LEX_CREATE_IF_NOT_EXISTS,
rows_affected)))
- goto done;
-
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- if (evex_is_running && et->status == MYSQL_EVENT_ENABLED)
{
- sp_name spn(et->dbname, et->name);
- ret= evex_load_and_compile_event(thd, &spn, true);
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ if (scheduler->initialized() && (ret= scheduler->add_event(thd, et, true)))
+ my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
}
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
-done:
/* No need to close the table, it will be closed in sql_parse::do_command */
DBUG_RETURN(ret);
@@ -1183,73 +1000,63 @@ done:
/*
- The function exported to the world for alteration of events.
+ The function exported to the world for alteration of events.
+
+ SYNOPSIS
+ Events::update_event()
+ thd THD
+ et event's data
+ new_name set in case of RENAME TO.
+
+ RETURN VALUE
+ 0 OK
+ !0 Error
- SYNOPSIS
- evex_update_event()
- thd THD
- et event's data
- new_name set in case of RENAME TO.
-
- NOTES
- et contains data about dbname and event name.
- new_name is the new name of the event, if not null (this means
- that RENAME TO was specified in the query)
+ NOTES
+ et contains data about dbname and event name.
+ new_name is the new name of the event, if not null (this means
+ that RENAME TO was specified in the query)
*/
int
-evex_update_event(THD *thd, Event_timed *et, sp_name *new_name,
- uint *rows_affected)
+Events::update_event(THD *thd, Event_timed *et, sp_name *new_name,
+ uint *rows_affected)
{
int ret;
- bool need_second_pass= true;
- DBUG_ENTER("evex_update_event");
+ DBUG_ENTER("Events::update_event");
DBUG_PRINT("enter", ("name: %*s", et->name.length, et->name.str));
-
/*
db_update_event() opens & closes the table to prevent
crash later in the code when loading and compiling the new definition.
Also on error conditions my_error() is called so no need to handle here
*/
- if ((ret= db_update_event(thd, et, new_name)))
- goto done;
-
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- if (!evex_is_running)
- UNLOCK_MUTEX_AND_BAIL_OUT(LOCK_evex_running, done);
-
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
- evex_remove_from_cache(&et->dbname, &et->name, false, false);
- if (et->status == MYSQL_EVENT_ENABLED)
- {
- if (new_name)
- ret= evex_load_and_compile_event(thd, new_name, false);
- else
- {
- sp_name spn(et->dbname, et->name);
- ret= evex_load_and_compile_event(thd, &spn, false);
- }
- if (ret == EVEX_COMPILE_ERROR)
- my_error(ER_EVENT_COMPILE_ERROR, MYF(0));
+ if (!(ret= db_update_event(thd, et, new_name)))
+ {
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ if (scheduler->initialized() &&
+ (ret= scheduler->replace_event(thd, et,
+ new_name? &new_name->m_db: NULL,
+ new_name? &new_name->m_name: NULL)))
+ my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
}
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
-done:
DBUG_RETURN(ret);
}
/*
- Drops an event
+ Drops an event
- SYNOPSIS
- db_drop_event()
- thd THD
- et event's name
- drop_if_exists if set and the event not existing => warning onto the stack
- rows_affected affected number of rows is returned heres
+ SYNOPSIS
+ db_drop_event()
+ thd THD
+ et event's name
+ drop_if_exists if set and the event not existing => warning onto the stack
+ rows_affected affected number of rows is returned heres
+
+ RETURN VALUE
+ 0 OK
+ !0 Error (my_error() called)
*/
int db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
@@ -1263,7 +1070,7 @@ int db_drop_event(THD *thd, Event_timed
ret= EVEX_OPEN_TABLE_FAILED;
thd->reset_n_backup_open_tables_state(&backup);
- if (evex_open_event_table(thd, TL_WRITE, &table))
+ if (Events::open_event_table(thd, TL_WRITE, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
goto done;
@@ -1303,58 +1110,54 @@ done:
/*
- Drops an event
+ Drops an event
- SYNOPSIS
- evex_drop_event()
- thd THD
- et event's name
- drop_if_exists if set and the event not existing => warning onto the stack
- rows_affected affected number of rows is returned heres
-
+ SYNOPSIS
+ Events::drop_event()
+ thd THD
+ et event's name
+ drop_if_exists if set and the event not existing => warning onto the stack
+ rows_affected affected number of rows is returned heres
+
+ RETURN VALUE
+ 0 OK
+ !0 Error (reported)
*/
int
-evex_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
- uint *rows_affected)
+Events::drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
+ uint *rows_affected)
{
- int ret= 0;
-
- DBUG_ENTER("evex_drop_event");
-
+ int ret;
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- if (evex_is_running)
- ret= evex_remove_from_cache(&et->dbname, &et->name, true, true);
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
- if (ret == 1)
- ret= 0;
- else if (ret == 0)
- ret= db_drop_event(thd, et, drop_if_exists, rows_affected);
- else
- my_error(ER_UNKNOWN_ERROR, MYF(0));
+ DBUG_ENTER("Events::drop_event");
+ if (!(ret= db_drop_event(thd, et, drop_if_exists, rows_affected)))
+ {
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ if (scheduler->initialized() && (ret= scheduler->drop_event(thd, et)))
+ my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
+ }
DBUG_RETURN(ret);
}
/*
- SHOW CREATE EVENT
+ SHOW CREATE EVENT
+
+ SYNOPSIS
+ Events::show_create_event()
+ thd THD
+ spn the name of the event (db, name)
+ definer the definer of the event
- SYNOPSIS
- evex_show_create_event()
- thd THD
- spn the name of the event (db, name)
- definer the definer of the event
-
- RETURNS
- 0 - OK
- 1 - Error during writing to the wire
+ RETURN VALUE
+ 0 OK
+ 1 Error during writing to the wire
*/
int
-evex_show_create_event(THD *thd, sp_name *spn)
+Events::show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
{
int ret;
Event_timed *et= NULL;
@@ -1364,10 +1167,10 @@ evex_show_create_event(THD *thd, sp_name
DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
thd->reset_n_backup_open_tables_state(&backup);
- ret= db_find_event(thd, spn, &et, NULL, thd->mem_root);
+ ret= db_find_event(thd, spn, &definer, &et, NULL, thd->mem_root);
thd->restore_backup_open_tables_state(&backup);
- if (et)
+ if (!ret)
{
Protocol *protocol= thd->protocol;
char show_str_buf[768];
@@ -1377,12 +1180,10 @@ evex_show_create_event(THD *thd, sp_name
ulong sql_mode_len=0;
show_str.length(0);
+ show_str.set_charset(system_charset_info);
if (et->get_create_event(thd, &show_str))
- {
- delete et;
- DBUG_RETURN(1);
- }
+ goto err;
field_list.push_back(new Item_empty_string("Event", NAME_LEN));
@@ -1396,201 +1197,216 @@ evex_show_create_event(THD *thd, sp_name
show_str.length()));
if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF))
- {
- delete et;
- DBUG_RETURN(1);
- }
+ goto err;
+
protocol->prepare_for_resend();
protocol->store(et->name.str, et->name.length, system_charset_info);
protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
- protocol->store(show_str.ptr(), show_str.length(), system_charset_info);
+ protocol->store(show_str.c_ptr(), show_str.length(), system_charset_info);
ret= protocol->write();
send_eof(thd);
- delete et;
}
-
+ delete et;
DBUG_RETURN(ret);
+err:
+ delete et;
+ DBUG_RETURN(1);
}
/*
- evex_drop_db_events - Drops all events in the selected database
+ Drops all events from a schema
- thd - Thread
- db - ASCIIZ the name of the database
-
- Returns:
- 0 - OK
- 1 - Failed to delete a specific row
- 2 - Got NULL while reading db name from a row
-
- Note:
- The algo is the following
- 1. Go through the in-memory cache, if the scheduler is working
- and for every event whose dbname matches the database we drop
- check whether is currently in execution:
- - Event_timed::can_spawn() returns true -> the event is not
- being executed in a child thread. The reason not to use
- Event_timed::is_running() is that the latter shows only if
- it is being executed, which is 99% of the time in the thread
- but there are some initiliazations before and after the
- anonymous SP is being called. So if we delete in this moment
- -=> *boom*, so we have to check whether the thread has been
- spawned and can_spawn() is the right method.
- - Event_timed::can_spawn() returns false -> being runned ATM
- just set the flags so it should drop itself.
+ SYNOPSIS
+ Events::drop_schema_events()
+ thd Thread
+ db ASCIIZ schema name
+
+ RETURN VALUE
+ 0 OK
+ !0 Error
*/
int
-evex_drop_db_events(THD *thd, char *db)
+Events::drop_schema_events(THD *thd, char *db)
{
- TABLE *table;
- READ_RECORD read_record_info;
int ret= 0;
- uint i;
LEX_STRING db_lex= {db, strlen(db)};
DBUG_ENTER("evex_drop_db_events");
- DBUG_PRINT("info",("dropping events from %s", db));
+ DBUG_PRINT("enter", ("dropping events from %s", db));
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ if (scheduler->initialized())
+ ret= scheduler->drop_schema_events(thd, &db_lex);
+ else
+ ret= db_drop_events_from_table(thd, &db_lex);
- if ((ret= evex_open_event_table(thd, TL_WRITE, &table)))
- {
- sql_print_error("Table mysql.event is damaged.");
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- DBUG_RETURN(SP_OPEN_TABLE_FAILED);
- }
+ DBUG_RETURN(ret);
+}
- DBUG_PRINT("info",("%d elements in the queue",
- evex_queue_num_elements(EVEX_EQ_NAME)));
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- if (!evex_is_running)
- goto skip_memory;
- for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i)
- {
- Event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, Event_timed*);
- if (sortcmp_lex_string(et->dbname, db_lex, system_charset_info))
- continue;
+/*
+ Drops all events in the selected database, from mysql.event.
- if (et->can_spawn_now_n_lock(thd))
- {
- DBUG_PRINT("info",("event %s not running - direct delete", et->name.str));
- if (!(ret= evex_db_find_event_aux(thd, et, table)))
- {
- DBUG_PRINT("info",("event %s found on disk", et->name.str));
- if ((ret= table->file->ha_delete_row(table->record[0])))
- {
- sql_print_error("Error while deleting a row - dropping "
- "a database. Skipping the rest.");
- my_error(ER_EVENT_DROP_FAILED, MYF(0), et->name.str);
- goto end;
- }
- DBUG_PRINT("info",("deleted event [%s] num [%d]. Time to free mem",
- et->name.str, i));
- }
- else if (ret == EVEX_KEY_NOT_FOUND)
- {
- sql_print_error("Expected to find event %s.%s of %s on disk-not there.",
- et->dbname.str, et->name.str, et->definer.str);
- }
- et->free_sp();
- delete et;
- et= 0;
- /* no need to call et->spawn_unlock because we already cleaned et */
- }
- else
- {
- DBUG_PRINT("info",("event %s is running. setting exec_no_more and dropped",
- et->name.str));
- et->flags|= EVENT_EXEC_NO_MORE;
- et->dropped= TRUE;
- }
- DBUG_PRINT("info",("%d elements in the queue",
- evex_queue_num_elements(EVEX_EQ_NAME)));
- evex_queue_delete_element(&EVEX_EQ_NAME, i);// 0 is top
- DBUG_PRINT("info",("%d elements in the queue",
- evex_queue_num_elements(EVEX_EQ_NAME)));
- /*
- decrease so we start at the same position, there will be
- less elements in the queue, it will still be ordered so on
- next iteration it will be again i the current element or if
- no more we finish.
- */
- --i;
- }
+ SYNOPSIS
+ evex_drop_db_events_from_table()
+ thd Thread
+ db Schema name
-skip_memory:
- /*
- The reasoning behind having two loops is the following:
- If there was only one loop, the table-scan, then for every element which
- matches, the queue in memory has to be searched to remove the element.
- While if we go first over the queue and remove what's in there we have only
- one pass over it and after finishing it, moving to table-scan for the disabled
- events. This needs quite less time and means quite less locking on
- LOCK_event_arrays.
- */
- DBUG_PRINT("info",("Mem-cache checked, now going to db for disabled events"));
+ RETURN VALUE
+ 0 OK
+ !0 Error from ha_delete_row
+*/
+
+int
+db_drop_events_from_table(THD *thd, LEX_STRING *db)
+{
+ int ret;
+ TABLE *table;
+ READ_RECORD read_record_info;
+ DBUG_ENTER("db_drop_events_from_table");
+ DBUG_PRINT("info", ("dropping events from %s", db->str));
+
+ if ((ret= Events::open_event_table(thd, TL_WRITE, &table)))
+ {
+ sql_print_error("Table mysql.event is damaged.");
+ DBUG_RETURN(ret);
+ }
/* 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);
+ init_read_record(&read_record_info, thd, table, NULL, 1, 0);
while (!(read_record_info.read_record(&read_record_info)) && !ret)
{
- char *et_db;
+ char *et_db= get_field(thd->mem_root,
+ table->field[Events::FIELD_DB]);
- if ((et_db= get_field(thd->mem_root, table->field[EVEX_FIELD_DB])) == NULL)
- {
- ret= 2;
- break;
- }
-
LEX_STRING et_db_lex= {et_db, strlen(et_db)};
- if (!sortcmp_lex_string(et_db_lex, db_lex, system_charset_info))
+ DBUG_PRINT("info", ("Current event %s.%s", et_db,
+ get_field(thd->mem_root,
+ table->field[Events::FIELD_NAME])));
+
+ if (!sortcmp_lex_string(et_db_lex, *db, system_charset_info))
{
- Event_timed ett;
- char *ptr;
-
- if ((ptr= get_field(thd->mem_root, table->field[EVEX_FIELD_STATUS]))
- == NullS)
- {
- sql_print_error("Error while loading from mysql.event. "
- "Table probably corrupted");
- goto end;
- }
- /*
- When not running nothing is in memory so we have to clean
- everything.
- We don't delete EVENT_ENABLED events when the scheduler is running
- because maybe this is an event which we asked to drop itself when
- it is finished and it hasn't finished yet, so we don't touch it.
- It will drop itself. The not running ENABLED events has been already
- deleted from ha_delete_row() above in the loop over the QUEUE
- (in case the executor is running).
- 'D' stands for DISABLED, 'E' for ENABLED - it's an enum
- */
- if ((evex_is_running && ptr[0] == 'D') || !evex_is_running)
- {
- DBUG_PRINT("info", ("Dropping %s.%s", et_db, ett.name.str));
- if ((ret= table->file->ha_delete_row(table->record[0])))
- {
- my_error(ER_EVENT_DROP_FAILED, MYF(0), ett.name.str);
- goto end;
- }
- }
+ DBUG_PRINT("info", ("Dropping"));
+ if ((ret= table->file->ha_delete_row(table->record[0])))
+ my_error(ER_EVENT_DROP_FAILED, MYF(0),
+ get_field(thd->mem_root,
+ table->field[Events::FIELD_NAME]));
}
}
- DBUG_PRINT("info",("Disk checked for disabled events. Finishing."));
-
-end:
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
end_read_record(&read_record_info);
-
thd->version--; /* Force close to free memory */
close_thread_tables(thd);
DBUG_RETURN(ret);
+}
+
+
+
+/*
+ Inits the scheduler's structures.
+
+ SYNOPSIS
+ Events::init()
+
+ NOTES
+ This function is not synchronized.
+
+ RETURN VALUE
+ 0 OK
+ 1 Error
+*/
+
+int
+Events::init()
+{
+ int ret= 0;
+ DBUG_ENTER("Events::init");
+
+ /* it should be an assignment! */
+ if (opt_event_scheduler)
+ {
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ DBUG_ASSERT(opt_event_scheduler == 1 || opt_event_scheduler == 2);
+ DBUG_RETURN(scheduler->init() ||
+ (opt_event_scheduler == 1? scheduler->start():
+ scheduler->start_suspended()));
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Cleans up scheduler's resources. Called at server shutdown.
+
+ SYNOPSIS
+ Events::shutdown()
+
+ NOTES
+ This function is not synchronized.
+*/
+
+void
+Events::shutdown()
+{
+ DBUG_ENTER("Events::shutdown");
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ if (scheduler->initialized())
+ {
+ scheduler->stop();
+ scheduler->destroy();
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Proxy for Event_scheduler::dump_internal_status
+
+ SYNOPSIS
+ Events::dump_internal_status()
+ thd Thread
+
+ RETURN VALUE
+ 0 OK
+ !0 Error
+*/
+
+int
+Events::dump_internal_status(THD *thd)
+{
+ return Event_scheduler::dump_internal_status(thd);
+}
+
+
+/*
+ Inits Events mutexes
+
+ SYNOPSIS
+ Events::init_mutexes()
+ thd Thread
+*/
+
+void
+Events::init_mutexes()
+{
+ Event_scheduler::init_mutexes();
+}
+
+
+/*
+ Destroys Events mutexes
+
+ SYNOPSIS
+ Events::destroy_mutexes()
+*/
+
+void
+Events::destroy_mutexes()
+{
+ Event_scheduler::destroy_mutexes();
}
--- 1.28/sql/event.h 2006-05-16 14:13:38 +02:00
+++ 1.29/sql/event.h 2006-05-25 11:31:13 +02:00
@@ -1,4 +1,6 @@
-/* Copyright (C) 2004-2005 MySQL AB
+#ifndef _EVENT_H_
+#define _EVENT_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
@@ -14,66 +16,109 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#ifndef _EVENT_H_
-#define _EVENT_H_
-#include "sp.h"
-#include "sp_head.h"
-#define EVEX_OK SP_OK
-#define EVEX_KEY_NOT_FOUND SP_KEY_NOT_FOUND
-#define EVEX_OPEN_TABLE_FAILED SP_OPEN_TABLE_FAILED
-#define EVEX_WRITE_ROW_FAILED SP_WRITE_ROW_FAILED
-#define EVEX_DELETE_ROW_FAILED SP_DELETE_ROW_FAILED
-#define EVEX_GET_FIELD_FAILED SP_GET_FIELD_FAILED
-#define EVEX_PARSE_ERROR SP_PARSE_ERROR
-#define EVEX_INTERNAL_ERROR SP_INTERNAL_ERROR
-#define EVEX_NO_DB_ERROR SP_NO_DB_ERROR
+#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 SP_BAD_IDENTIFIER
-#define EVEX_BODY_TOO_LONG SP_BODY_TOO_LONG
-#define EVEX_BAD_PARAMS -21
-#define EVEX_NOT_RUNNING -22
-#define EVEX_MICROSECOND_UNSUP -23
+#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)
-extern ulong opt_event_executor;
+class Event_timed;
-enum enum_event_on_completion
+class Events
{
- MYSQL_EVENT_ON_COMPLETION_DROP = 1,
- MYSQL_EVENT_ON_COMPLETION_PRESERVE
-};
+public:
+ static ulong opt_event_scheduler;
+ static TYPELIB opt_typelib;
-enum enum_event_status
-{
- MYSQL_EVENT_ENABLED = 1,
- MYSQL_EVENT_DISABLED
+ enum enum_table_field
+ {
+ 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 :) */
+ };
+
+ static int
+ create_event(THD *thd, Event_timed *et, uint create_options,
+ uint *rows_affected);
+
+ static int
+ update_event(THD *thd, Event_timed *et, sp_name *new_name,
+ uint *rows_affected);
+
+ static int
+ drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
+ uint *rows_affected);
+
+ static int
+ open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
+
+ static int
+ show_create_event(THD *thd, sp_name *spn, LEX_STRING definer);
+
+ static int
+ reconstruct_interval_expression(String *buf, interval_type interval,
+ longlong expression);
+
+ static int
+ drop_schema_events(THD *thd, char *db);
+
+ static int
+ dump_internal_status(THD *thd);
+
+ static int
+ init();
+
+ static void
+ shutdown();
+
+ static void
+ init_mutexes();
+
+ static void
+ destroy_mutexes();
+
+
+private:
+ /* Prevent use of these */
+ Events(const Events &);
+ void operator=(Events &);
};
-enum evex_table_field
-{
- EVEX_FIELD_DB = 0,
- EVEX_FIELD_NAME,
- EVEX_FIELD_BODY,
- EVEX_FIELD_DEFINER,
- EVEX_FIELD_EXECUTE_AT,
- EVEX_FIELD_INTERVAL_EXPR,
- EVEX_FIELD_TRANSIENT_INTERVAL,
- EVEX_FIELD_CREATED,
- EVEX_FIELD_MODIFIED,
- EVEX_FIELD_LAST_EXECUTED,
- EVEX_FIELD_STARTS,
- EVEX_FIELD_ENDS,
- EVEX_FIELD_STATUS,
- EVEX_FIELD_ON_COMPLETION,
- EVEX_FIELD_SQL_MODE,
- EVEX_FIELD_COMMENT,
- EVEX_FIELD_COUNT /* a cool trick to count the number of fields :) */
-} ;
+
+
+class sp_head;
class Event_timed
{
@@ -82,12 +127,26 @@ class 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;
@@ -111,8 +170,8 @@ public:
ulonglong created;
ulonglong modified;
- enum enum_event_on_completion on_completion;
- enum enum_event_status status;
+ enum enum_on_completion on_completion;
+ enum enum_status status;
sp_head *sphead;
ulong sql_mode;
const uchar *body_begin;
@@ -153,36 +212,15 @@ public:
DBUG_ASSERT(0);
}
+ Event_timed();
- Event_timed():in_spawned_thread(0),locked_by_thread_id(0),
- running(0), status_changed(false),
- last_executed_changed(false), expression(0), created(0),
- modified(0), on_completion(MYSQL_EVENT_ON_COMPLETION_DROP),
- status(MYSQL_EVENT_ENABLED), sphead(0), sql_mode(0),
- body_begin(0), dropped(false),
- free_sphead_on_delete(true), flags(0)
-
- {
- pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST);
- init();
- }
-
- ~Event_timed()
- {
- deinit_mutexes();
-
- if (free_sphead_on_delete)
- free_sp();
- }
+ ~Event_timed();
void
init();
-
+
void
- deinit_mutexes()
- {
- pthread_mutex_destroy(&this->LOCK_running);
- }
+ deinit_mutexes();
int
init_definer(THD *thd);
@@ -214,12 +252,12 @@ public:
bool
compute_next_execution_time();
- void
- mark_last_executed(THD *thd);
-
int
drop(THD *thd);
+ void
+ mark_last_executed(THD *thd);
+
bool
update_fields(THD *thd);
@@ -227,142 +265,32 @@ public:
get_create_event(THD *thd, String *buf);
int
- execute(THD *thd, MEM_ROOT *mem_root= NULL);
+ execute(THD *thd, MEM_ROOT *mem_root);
int
- compile(THD *thd, MEM_ROOT *mem_root= NULL);
-
- my_bool
- is_running()
- {
- my_bool ret;
-
- VOID(pthread_mutex_lock(&this->LOCK_running));
- ret= running;
- VOID(pthread_mutex_unlock(&this->LOCK_running));
-
- return ret;
- }
-
- /*
- Checks whether the object is being used in a spawned thread.
- This method is for very basic checking. Use ::can_spawn_now_n_lock()
- for most of the cases.
- */
+ compile(THD *thd, MEM_ROOT *mem_root);
- my_bool
- can_spawn_now()
- {
- my_bool ret;
- VOID(pthread_mutex_lock(&this->LOCK_running));
- ret= !in_spawned_thread;
- VOID(pthread_mutex_unlock(&this->LOCK_running));
- return ret;
- }
-
- /*
- Checks whether this thread can lock the object for modification ->
- preventing being spawned for execution, and locks if possible.
- use ::can_spawn_now() only for basic checking because a race
- condition may occur between the check and eventual modification (deletion)
- of the object.
- */
-
- my_bool
- can_spawn_now_n_lock(THD *thd);
-
- int
- spawn_unlock(THD *thd);
+ bool
+ is_running();
int
- spawn_now(void * (*thread_func)(void*));
+ spawn_now(void * (*thread_func)(void*), void *arg);
- void
+ bool
spawn_thread_finish(THD *thd);
void
- free_sp()
- {
- delete sphead;
- sphead= 0;
- }
-protected:
+ free_sp();
+
bool
- change_security_context(THD *thd, Security_context *s_ctx,
- Security_context **backup);
+ has_equal_db(Event_timed *etn);
+
+ int
+ kill_thread(THD *thd);
void
- restore_security_context(THD *thd, Security_context *backup);
+ set_thread_id(ulong tid) { thread_id= tid; }
};
-
-int
-evex_create_event(THD *thd, Event_timed *et, uint create_options,
- uint *rows_affected);
-
-int
-evex_update_event(THD *thd, Event_timed *et, sp_name *new_name,
- uint *rows_affected);
-
-int
-evex_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
- uint *rows_affected);
-
-int
-evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
-
-int
-evex_show_create_event(THD *thd, sp_name *spn);
-
-int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
-
-int
-event_reconstruct_interval_expression(String *buf,
- interval_type interval,
- longlong expression);
-
-int
-evex_drop_db_events(THD *thd, char *db);
-
-
-int
-init_events();
-
-void
-shutdown_events();
-
-
-// auxiliary
-int
-event_timed_compare(Event_timed **a, Event_timed **b);
-
-
-
-/*
-CREATE TABLE event (
- db char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
- name char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
- body longblob NOT NULL,
- definer char(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
- execute_at DATETIME default NULL,
- interval_value int(11) default NULL,
- interval_field 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') default NULL,
- created TIMESTAMP NOT NULL,
- modified TIMESTAMP NOT NULL,
- last_executed DATETIME default NULL,
- starts DATETIME default NULL,
- ends DATETIME default NULL,
- status ENUM('ENABLED','DISABLED') NOT NULL default 'ENABLED',
- on_completion ENUM('DROP','PRESERVE') NOT NULL default 'DROP',
- comment varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
- PRIMARY KEY (definer,db,name)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events';
-*/
#endif /* _EVENT_H_ */
--- 1.21/sql/event_priv.h 2006-05-16 14:13:38 +02:00
+++ 1.22/sql/event_priv.h 2006-05-25 10:40:43 +02:00
@@ -1,4 +1,6 @@
-/* Copyright (C) 2004-2005 MySQL AB
+#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
@@ -14,8 +16,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#ifndef _EVENT_PRIV_H_
-#define _EVENT_PRIV_H_
#include "mysql_priv.h"
@@ -23,11 +23,6 @@
#define EVENT_EXEC_ALREADY_EXEC 1
#define EVENT_EXEC_CANT_FORK 2
-#define EVEX_USE_QUEUE
-
-#define UNLOCK_MUTEX_AND_BAIL_OUT(__mutex, __label) \
- { VOID(pthread_mutex_unlock(&__mutex)); goto __label; }
-
#define EVEX_DB_FIELD_LEN 64
#define EVEX_NAME_FIELD_LEN 64
#define EVEX_MAX_INTERVAL_VALUE 2147483647L
@@ -43,39 +38,49 @@ evex_db_find_event_by_name(THD *thd, con
int
event_timed_compare_q(void *vptr, byte* a, byte *b);
-int db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
- uint *rows_affected);
-
-
-#define EXEC_QUEUE_QUEUE_NAME executing_queue
-#define EXEC_QUEUE_DARR_NAME evex_executing_queue
-
+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, LEX_STRING *definer, Event_timed **ett,
+ TABLE *tbl, MEM_ROOT *root);
-#define EVEX_QUEUE_TYPE QUEUE
-#define EVEX_PTOQEL byte *
+int
+db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
+ uint *rows_affected);
-#define EVEX_EQ_NAME executing_queue
-#define evex_queue_first_element(queue, __cast) ((__cast)queue_top(queue))
-#define evex_queue_element(queue, idx, __cast) ((__cast)queue_element(queue, idx))
-#define evex_queue_delete_element(queue, idx) queue_remove(queue, idx)
-#define evex_queue_destroy(queue) delete_queue(queue)
-#define evex_queue_first_updated(queue) queue_replaced(queue)
-#define evex_queue_insert(queue, element) queue_insert_safe(queue, element);
+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
-evex_queue_init(EVEX_QUEUE_TYPE *queue);
-
-#define evex_queue_num_elements(queue) queue.elements
-
-
-extern bool evex_is_running;
-extern MEM_ROOT evex_mem_root;
-extern pthread_mutex_t LOCK_event_arrays,
- LOCK_workers_count,
- LOCK_evex_running;
-extern ulonglong evex_main_thread_id;
-extern QUEUE EVEX_EQ_NAME;
+restore_security_context(THD *thd, Security_context *backup);
#endif /* _EVENT_PRIV_H_ */
--- 1.52/sql/event_timed.cc 2006-05-16 14:13:38 +02:00
+++ 1.53/sql/event_timed.cc 2006-05-25 10:40:43 +02:00
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2005 MySQL AB
+/* 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
@@ -17,7 +17,82 @@
#define MYSQL_LEX 1
#include "event_priv.h"
#include "event.h"
-#include "sp.h"
+#include "sp_head.h"
+
+
+/*
+ Constructor
+
+ SYNOPSIS
+ Event_timed::Event_timed()
+*/
+
+Event_timed::Event_timed():in_spawned_thread(0),locked_by_thread_id(0),
+ running(0), thread_id(0), status_changed(false),
+ last_executed_changed(false), expression(0),
+ created(0), modified(0),
+ on_completion(Event_timed::ON_COMPLETION_DROP),
+ status(Event_timed::ENABLED), sphead(0),
+ sql_mode(0), body_begin(0), dropped(false),
+ free_sphead_on_delete(true), flags(0)
+
+{
+ pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&this->COND_finished, NULL);
+ init();
+}
+
+
+/*
+ Destructor
+
+ SYNOPSIS
+ Event_timed::~Event_timed()
+*/
+
+Event_timed::~Event_timed()
+{
+ deinit_mutexes();
+
+ if (free_sphead_on_delete)
+ free_sp();
+}
+
+
+/*
+ Destructor
+
+ SYNOPSIS
+ Event_timed::~deinit_mutexes()
+*/
+
+void
+Event_timed::deinit_mutexes()
+{
+ pthread_mutex_destroy(&this->LOCK_running);
+ pthread_cond_destroy(&this->COND_finished);
+}
+
+
+/*
+ Checks whether the event is running
+
+ SYNOPSIS
+ Event_timed::is_running()
+*/
+
+bool
+Event_timed::is_running()
+{
+ bool ret;
+
+ VOID(pthread_mutex_lock(&this->LOCK_running));
+ ret= running;
+ VOID(pthread_mutex_unlock(&this->LOCK_running));
+
+ return ret;
+}
+
/*
Init all member variables
@@ -238,7 +313,7 @@ Event_timed::init_execute_at(THD *thd, I
expr how much?
new_interval what is the interval
- RETURNS
+ RETURN VALUE
0 OK
EVEX_PARSE_ERROR fix_fields failed
EVEX_BAD_PARAMS Interval is not positive
@@ -342,7 +417,7 @@ Event_timed::init_interval(THD *thd, Ite
DATE_ADD(NOW(), INTERVAL 1 DAY) -- start tommorow at
same time.
- RETURNS
+ RETURN VALUE
0 OK
EVEX_PARSE_ERROR fix_fields failed
EVEX_BAD_PARAMS starts before now
@@ -408,7 +483,7 @@ Event_timed::init_starts(THD *thd, Item
DATE_ADD(NOW(), INTERVAL 1 DAY) -- end tommorow at
same time.
- RETURNS
+ RETURN VALUE
0 OK
EVEX_PARSE_ERROR fix_fields failed
ER_WRONG_VALUE starts distant date (after year 2037)
@@ -492,6 +567,9 @@ Event_timed::init_comment(THD *thd, LEX_
SYNOPSIS
Event_timed::init_definer()
+
+ RETURN VALUE
+ 0 OK
*/
int
@@ -534,6 +612,10 @@ Event_timed::init_definer(THD *thd)
SYNOPSIS
Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
+ RETURN VALUE
+ 0 OK
+ EVEX_GET_FIELD_FAILED Error
+
NOTES
This method is silent on errors and should behave like that. Callers
should handle throwing of error messages. The reason is that the class
@@ -555,29 +637,29 @@ Event_timed::load_from_row(MEM_ROOT *mem
et= this;
- if (table->s->fields != EVEX_FIELD_COUNT)
+ if (table->s->fields != Events::FIELD_COUNT)
goto error;
if ((et->dbname.str= get_field(mem_root,
- table->field[EVEX_FIELD_DB])) == NULL)
+ table->field[Events::FIELD_DB])) == NULL)
goto error;
et->dbname.length= strlen(et->dbname.str);
if ((et->name.str= get_field(mem_root,
- table->field[EVEX_FIELD_NAME])) == NULL)
+ table->field[Events::FIELD_NAME])) == NULL)
goto error;
et->name.length= strlen(et->name.str);
if ((et->body.str= get_field(mem_root,
- table->field[EVEX_FIELD_BODY])) == NULL)
+ table->field[Events::FIELD_BODY])) == NULL)
goto error;
et->body.length= strlen(et->body.str);
if ((et->definer.str= get_field(mem_root,
- table->field[EVEX_FIELD_DEFINER])) == NullS)
+ table->field[Events::FIELD_DEFINER])) == NullS)
goto error;
et->definer.length= strlen(et->definer.str);
@@ -594,69 +676,71 @@ Event_timed::load_from_row(MEM_ROOT *mem
et->definer_host.str= strmake_root(mem_root, ptr + 1, len);/* 1:because of @*/
et->definer_host.length= len;
- et->starts_null= table->field[EVEX_FIELD_STARTS]->is_null();
- res1= table->field[EVEX_FIELD_STARTS]->get_date(&et->starts,TIME_NO_ZERO_DATE);
+ et->starts_null= table->field[Events::FIELD_STARTS]->is_null();
+ res1= table->field[Events::FIELD_STARTS]->
+ get_date(&et->starts,TIME_NO_ZERO_DATE);
- et->ends_null= table->field[EVEX_FIELD_ENDS]->is_null();
- res2= table->field[EVEX_FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
+ et->ends_null= table->field[Events::FIELD_ENDS]->is_null();
+ res2= table->field[Events::FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
- if (!table->field[EVEX_FIELD_INTERVAL_EXPR]->is_null())
- et->expression= table->field[EVEX_FIELD_INTERVAL_EXPR]->val_int();
+ if (!table->field[Events::FIELD_INTERVAL_EXPR]->is_null())
+ et->expression= table->field[Events::FIELD_INTERVAL_EXPR]->val_int();
else
et->expression= 0;
/*
If res1 and res2 are true then both fields are empty.
- Hence if EVEX_FIELD_EXECUTE_AT is empty there is an error.
+ Hence if Events::FIELD_EXECUTE_AT is empty there is an error.
*/
- et->execute_at_null= table->field[EVEX_FIELD_EXECUTE_AT]->is_null();
+ et->execute_at_null=
+ table->field[Events::FIELD_EXECUTE_AT]->is_null();
DBUG_ASSERT(!(et->starts_null && et->ends_null && !et->expression &&
et->execute_at_null));
if (!et->expression &&
- table->field[EVEX_FIELD_EXECUTE_AT]->get_date(&et->execute_at,
- TIME_NO_ZERO_DATE))
+ table->field[Events::FIELD_EXECUTE_AT]-> get_date(&et->execute_at,
+ TIME_NO_ZERO_DATE))
goto error;
/*
In DB the values start from 1 but enum interval_type starts
from 0
*/
- if (!table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->is_null())
- et->interval= (interval_type)
- ((ulonglong) table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
+ if (!table->field[Events::FIELD_TRANSIENT_INTERVAL]->is_null())
+ et->interval= (interval_type) ((ulonglong)
+ table->field[Events::FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
else
et->interval= (interval_type) 0;
- et->created= table->field[EVEX_FIELD_CREATED]->val_int();
- et->modified= table->field[EVEX_FIELD_MODIFIED]->val_int();
+ et->created= table->field[Events::FIELD_CREATED]->val_int();
+ et->modified= table->field[Events::FIELD_MODIFIED]->val_int();
- table->field[EVEX_FIELD_LAST_EXECUTED]->
+ table->field[Events::FIELD_LAST_EXECUTED]->
get_date(&et->last_executed, TIME_NO_ZERO_DATE);
last_executed_changed= false;
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
- if ((ptr= get_field(mem_root, table->field[EVEX_FIELD_STATUS])) == NullS)
+ if ((ptr= get_field(mem_root, table->field[Events::FIELD_STATUS])) == NullS)
goto error;
DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", et->name.str, ptr));
- et->status= (ptr[0]=='E'? MYSQL_EVENT_ENABLED:MYSQL_EVENT_DISABLED);
+ et->status= (ptr[0]=='E'? Event_timed::ENABLED:Event_timed::DISABLED);
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
if ((ptr= get_field(mem_root,
- table->field[EVEX_FIELD_ON_COMPLETION])) == NullS)
+ table->field[Events::FIELD_ON_COMPLETION])) == NullS)
goto error;
- et->on_completion= (ptr[0]=='D'? MYSQL_EVENT_ON_COMPLETION_DROP:
- MYSQL_EVENT_ON_COMPLETION_PRESERVE);
+ et->on_completion= (ptr[0]=='D'? Event_timed::ON_COMPLETION_DROP:
+ Event_timed::ON_COMPLETION_PRESERVE);
- et->comment.str= get_field(mem_root, table->field[EVEX_FIELD_COMMENT]);
+ et->comment.str= get_field(mem_root, table->field[Events::FIELD_COMMENT]);
if (et->comment.str != NullS)
et->comment.length= strlen(et->comment.str);
else
et->comment.length= 0;
- et->sql_mode= (ulong) table->field[EVEX_FIELD_SQL_MODE]->val_int();
+ et->sql_mode= (ulong) table->field[Events::FIELD_SQL_MODE]->val_int();
DBUG_RETURN(0);
error:
@@ -676,7 +760,7 @@ error:
i_value quantity of time type interval to add
i_type type of interval to add (SECOND, MINUTE, HOUR, WEEK ...)
- RETURNS
+ RETURN VALUE
0 OK
1 Error
@@ -834,6 +918,10 @@ done:
SYNOPSIS
Event_timed::compute_next_execution_time()
+ RETURN VALUE
+ FALSE OK
+ TRUE Error
+
NOTES
The time is set in execute_at, if no more executions the latter is set to
0000-00-00.
@@ -843,7 +931,6 @@ bool
Event_timed::compute_next_execution_time()
{
TIME time_now;
- my_time_t now;
int tmp;
DBUG_ENTER("Event_timed::compute_next_execution_time");
@@ -852,7 +939,7 @@ Event_timed::compute_next_execution_time
TIME_to_ulonglong_datetime(&ends),
TIME_to_ulonglong_datetime(&last_executed)));
- if (status == MYSQL_EVENT_DISABLED)
+ if (status == Event_timed::DISABLED)
{
DBUG_PRINT("compute_next_execution_time",
("Event %s is DISABLED", name.str));
@@ -866,14 +953,15 @@ Event_timed::compute_next_execution_time
{
DBUG_PRINT("info",("One-time event %s.%s of was already executed",
dbname.str, name.str, definer.str));
- dropped= (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP);
+ dropped= (on_completion == Event_timed::ON_COMPLETION_DROP);
DBUG_PRINT("info",("One-time event will be dropped=%d.", dropped));
- status= MYSQL_EVENT_DISABLED;
+ status= Event_timed::DISABLED;
status_changed= true;
}
goto ret;
}
+ current_thd->end_time();
my_tz_UTC->gmt_sec_to_TIME(&time_now, current_thd->query_start());
DBUG_PRINT("info",("NOW=[%llu]", TIME_to_ulonglong_datetime(&time_now)));
@@ -885,9 +973,9 @@ Event_timed::compute_next_execution_time
/* time_now is after ends. don't execute anymore */
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
execute_at_null= TRUE;
- if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
+ if (on_completion == Event_timed::ON_COMPLETION_DROP)
dropped= true;
- status= MYSQL_EVENT_DISABLED;
+ status= Event_timed::DISABLED;
status_changed= true;
goto ret;
@@ -937,7 +1025,6 @@ Event_timed::compute_next_execution_time
{
TIME next_exec;
- DBUG_PRINT("info", ("Executed at least once"));
if (get_next_time(&next_exec, &starts, &time_now,
last_executed.year? &last_executed:&starts,
expression, interval))
@@ -946,12 +1033,15 @@ Event_timed::compute_next_execution_time
/* There was previous execution */
if (my_time_compare(&ends, &next_exec) == -1)
{
- DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
+ DBUG_PRINT("info", ("Next execution of %s after ENDS. Stop executing.",
+ name.str));
/* Next execution after ends. No more executions */
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
execute_at_null= TRUE;
- if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
+ if (on_completion == Event_timed::ON_COMPLETION_DROP)
dropped= true;
+ status= Event_timed::DISABLED;
+ status_changed= true;
}
else
{
@@ -1006,7 +1096,6 @@ Event_timed::compute_next_execution_time
{
TIME next_exec;
- DBUG_PRINT("info", ("Executed at least once."));
if (get_next_time(&next_exec, &starts, &time_now,
last_executed.year? &last_executed:&starts,
expression, interval))
@@ -1042,7 +1131,9 @@ Event_timed::compute_next_execution_time
DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
execute_at_null= TRUE;
- if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
+ status= Event_timed::DISABLED;
+ status_changed= true;
+ if (on_completion == Event_timed::ON_COMPLETION_DROP)
dropped= true;
}
else
@@ -1083,9 +1174,6 @@ Event_timed::mark_last_executed(THD *thd
my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start());
last_executed= time_now; /* was execute_at */
-#ifdef ANDREY_0
- last_executed= execute_at;
-#endif
last_executed_changed= true;
}
@@ -1125,7 +1213,7 @@ Event_timed::drop(THD *thd)
RETURN VALUE
0 OK
- SP_OPEN_TABLE_FAILED Error while opening mysql.event for writing
+ EVEX_OPEN_TABLE_FAILED Error while opening mysql.event for writing
EVEX_WRITE_ROW_FAILED On error to write to disk
others return code from SE in case deletion of the event
@@ -1149,9 +1237,9 @@ Event_timed::update_fields(THD *thd)
thd->reset_n_backup_open_tables_state(&backup);
- if (evex_open_event_table(thd, TL_WRITE, &table))
+ if (Events::open_event_table(thd, TL_WRITE, &table))
{
- ret= SP_OPEN_TABLE_FAILED;
+ ret= EVEX_OPEN_TABLE_FAILED;
goto done;
}
@@ -1165,15 +1253,15 @@ Event_timed::update_fields(THD *thd)
if (last_executed_changed)
{
- table->field[EVEX_FIELD_LAST_EXECUTED]->set_notnull();
- table->field[EVEX_FIELD_LAST_EXECUTED]->store_time(&last_executed,
- MYSQL_TIMESTAMP_DATETIME);
+ table->field[Events::FIELD_LAST_EXECUTED]->set_notnull();
+ table->field[Events::FIELD_LAST_EXECUTED]->store_time(&last_executed,
+ MYSQL_TIMESTAMP_DATETIME);
last_executed_changed= false;
}
if (status_changed)
{
- table->field[EVEX_FIELD_STATUS]->set_notnull();
- table->field[EVEX_FIELD_STATUS]->store((longlong)status, true);
+ table->field[Events::FIELD_STATUS]->set_notnull();
+ table->field[Events::FIELD_STATUS]->store((longlong)status, true);
status_changed= false;
}
@@ -1215,8 +1303,8 @@ Event_timed::get_create_event(THD *thd,
DBUG_ENTER("get_create_event");
DBUG_PRINT("ret_info",("body_len=[%d]body=[%s]", body.length, body.str));
- if (expression &&
- event_reconstruct_interval_expression(&expr_buf, interval, expression))
+ if (expression && Events::reconstruct_interval_expression(&expr_buf, interval,
+ expression))
DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
buf->append(STRING_WITH_LEN("CREATE EVENT "));
@@ -1243,12 +1331,12 @@ Event_timed::get_create_event(THD *thd,
buf->append(STRING_WITH_LEN("'"));
}
- if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
+ if (on_completion == Event_timed::ON_COMPLETION_DROP)
buf->append(STRING_WITH_LEN(" ON COMPLETION NOT PRESERVE "));
else
buf->append(STRING_WITH_LEN(" ON COMPLETION PRESERVE "));
- if (status == MYSQL_EVENT_ENABLED)
+ if (status == Event_timed::ENABLED)
buf->append(STRING_WITH_LEN("ENABLE"));
else
buf->append(STRING_WITH_LEN("DISABLE"));
@@ -1273,7 +1361,7 @@ Event_timed::get_create_event(THD *thd,
thd THD
mem_root If != NULL use it to compile the event on it
- RETURNS
+ RETURN VALUE
0 success
-99 No rights on this.dbname.str
-100 event in execution (parallel execution is impossible)
@@ -1283,7 +1371,6 @@ Event_timed::get_create_event(THD *thd,
int
Event_timed::execute(THD *thd, MEM_ROOT *mem_root)
{
- Security_context *save_ctx;
/* this one is local and not needed after exec */
Security_context security_ctx;
int ret= 0;
@@ -1301,16 +1388,8 @@ Event_timed::execute(THD *thd, MEM_ROOT
running= true;
VOID(pthread_mutex_unlock(&this->LOCK_running));
- DBUG_PRINT("info", ("master_access=%d db_access=%d",
- thd->security_ctx->master_access, thd->security_ctx->db_access));
- change_security_context(thd, &security_ctx, &save_ctx);
- DBUG_PRINT("info", ("master_access=%d db_access=%d",
- thd->security_ctx->master_access, thd->security_ctx->db_access));
-
if (!sphead && (ret= compile(thd, mem_root)))
goto done;
- /* Now we are sure we have valid this->sphead so we can copy the context */
- sphead->m_security_ctx= security_ctx;
/*
THD::~THD will clean this or if there is DROP DATABASE in the SP then
it will be free there. It should not point to our buffer which is allocated
@@ -1334,12 +1413,11 @@ Event_timed::execute(THD *thd, MEM_ROOT
definer_host.str, dbname.str));
ret= -99;
}
- restore_security_context(thd, save_ctx);
- DBUG_PRINT("info", ("master_access=%d db_access=%d",
- thd->security_ctx->master_access, thd->security_ctx->db_access));
VOID(pthread_mutex_lock(&this->LOCK_running));
running= false;
+ /* Will compile every time a new sp_head on different root */
+ free_sp();
VOID(pthread_mutex_unlock(&this->LOCK_running));
done:
@@ -1361,55 +1439,16 @@ done:
/*
- Switches the security context
- Synopsis
- Event_timed::change_security_context()
- thd - thread
- backup - where to store the old context
-
- RETURN
- 0 - OK
- 1 - Error (generates error too)
-*/
-bool
-Event_timed::change_security_context(THD *thd, Security_context *s_ctx,
- Security_context **backup)
-{
- DBUG_ENTER("Event_timed::change_security_context");
- DBUG_PRINT("info",("%s@%s@%s",definer_user.str,definer_host.str, dbname.str));
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- s_ctx->init();
- *backup= 0;
- if (acl_getroot_no_password(s_ctx, definer_user.str, definer_host.str,
- definer_host.str, dbname.str))
- {
- my_error(ER_NO_SUCH_USER, MYF(0), definer_user.str, definer_host.str);
- DBUG_RETURN(true);
- }
- *backup= thd->security_ctx;
- thd->security_ctx= s_ctx;
-#endif
- DBUG_RETURN(false);
-}
-
-
-/*
- Restores the security context
- Synopsis
- Event_timed::restore_security_context()
- thd - thread
- backup - switch to this context
+ Frees the memory of the sp_head object we hold
+ SYNOPSIS
+ Event_timed::free_sp()
*/
void
-Event_timed::restore_security_context(THD *thd, Security_context *backup)
+Event_timed::free_sp()
{
- DBUG_ENTER("Event_timed::restore_security_context");
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (backup)
- thd->security_ctx= backup;
-#endif
- DBUG_VOID_RETURN;
+ delete sphead;
+ sphead= 0;
}
@@ -1445,6 +1484,9 @@ Event_timed::compile(THD *thd, MEM_ROOT
CHARSET_INFO *old_character_set_client,
*old_collation_connection,
*old_character_set_results;
+ Security_context *save_ctx;
+ /* this one is local and not needed after exec */
+ Security_context security_ctx;
DBUG_ENTER("Event_timed::compile");
@@ -1488,8 +1530,10 @@ Event_timed::compile(THD *thd, MEM_ROOT
thd->query= show_create.c_ptr();
thd->query_length= show_create.length();
- DBUG_PRINT("Event_timed::compile", ("query:%s",thd->query));
+ DBUG_PRINT("info", ("query:%s",thd->query));
+ change_security_context(thd, definer_user, definer_host, dbname,
+ &security_ctx, &save_ctx);
thd->lex= &lex;
lex_start(thd, (uchar*)thd->query, thd->query_length);
lex.et_compile_phase= TRUE;
@@ -1527,6 +1571,7 @@ done:
lex.et->deinit_mutexes();
lex_end(&lex);
+ restore_security_context(thd, save_ctx);
DBUG_PRINT("note", ("return old data on its place. set back NAMES"));
thd->lex= old_lex;
@@ -1548,72 +1593,63 @@ done:
}
-/*
- Checks whether this thread can lock the object for modification ->
- preventing being spawned for execution, and locks if possible.
- use ::can_spawn_now() only for basic checking because a race
- condition may occur between the check and eventual modification (deletion)
- of the object.
-
- Returns
- true - locked
- false - cannot lock
-*/
-
-my_bool
-Event_timed::can_spawn_now_n_lock(THD *thd)
-{
- my_bool ret= FALSE;
- VOID(pthread_mutex_lock(&this->LOCK_running));
- if (!in_spawned_thread)
- {
- in_spawned_thread= TRUE;
- ret= TRUE;
- locked_by_thread_id= thd->thread_id;
- }
- VOID(pthread_mutex_unlock(&this->LOCK_running));
- return ret;
-}
-
-
extern pthread_attr_t connection_attrib;
/*
Checks whether is possible and forks a thread. Passes self as argument.
- Returns
- EVENT_EXEC_STARTED - OK
- EVENT_EXEC_ALREADY_EXEC - Thread not forked, already working
- EVENT_EXEC_CANT_FORK - Unable to spawn thread (error)
+ RETURN VALUE
+ EVENT_EXEC_STARTED OK
+ EVENT_EXEC_ALREADY_EXEC Thread not forked, already working
+ EVENT_EXEC_CANT_FORK Unable to spawn thread (error)
*/
int
-Event_timed::spawn_now(void * (*thread_func)(void*))
+Event_timed::spawn_now(void * (*thread_func)(void*), void *arg)
{
+ THD *thd= current_thd;
int ret= EVENT_EXEC_STARTED;
- static uint exec_num= 0;
DBUG_ENTER("Event_timed::spawn_now");
- DBUG_PRINT("info", ("this=0x%lx", this));
DBUG_PRINT("info", ("[%s.%s]", dbname.str, name.str));
VOID(pthread_mutex_lock(&this->LOCK_running));
+
+ DBUG_PRINT("info", ("SCHEDULER: execute_at of %s is %lld", name.str,
+ TIME_to_ulonglong_datetime(&execute_at)));
+ mark_last_executed(thd);
+ if (compute_next_execution_time())
+ {
+ sql_print_error("SCHEDULER: Error while computing time of %s.%s . "
+ "Disabling after execution.", dbname.str, name.str);
+ status= DISABLED;
+ }
+ DBUG_PRINT("evex manager", ("[%10s] next exec at [%llu]", name.str,
+ TIME_to_ulonglong_datetime(&execute_at)));
+ /*
+ 1. For one-time event : year is > 0 and expression is 0
+ 2. For recurring, expression is != -=> check execute_at_null in this case
+ */
+ if ((execute_at.year && !expression) || execute_at_null)
+ {
+ sql_print_information("SCHEDULER: [%s.%s of %s] no more executions "
+ "after this one", dbname.str, name.str,
+ definer.str);
+ flags |= EVENT_EXEC_NO_MORE | EVENT_FREE_WHEN_FINISHED;
+ }
+
+ update_fields(thd);
+
if (!in_spawned_thread)
{
pthread_t th;
in_spawned_thread= true;
- if (pthread_create(&th, &connection_attrib, thread_func, (void*)this))
+
+ if (pthread_create(&th, &connection_attrib, thread_func, arg))
{
DBUG_PRINT("info", ("problem while spawning thread"));
ret= EVENT_EXEC_CANT_FORK;
in_spawned_thread= false;
}
-#ifndef DBUG_OFF
- else
- {
- sql_print_information("SCHEDULER: Started thread %d", ++exec_num);
- DBUG_PRINT("info", ("thread spawned"));
- }
-#endif
}
else
{
@@ -1626,55 +1662,207 @@ Event_timed::spawn_now(void * (*thread_f
}
-void
+bool
Event_timed::spawn_thread_finish(THD *thd)
{
+ bool should_free;
DBUG_ENTER("Event_timed::spawn_thread_finish");
- VOID(pthread_mutex_lock(&this->LOCK_running));
+ VOID(pthread_mutex_lock(&LOCK_running));
in_spawned_thread= false;
- if ((flags & EVENT_EXEC_NO_MORE) || status == MYSQL_EVENT_DISABLED)
+ DBUG_PRINT("info", ("Sending COND_finished for thread %d", thread_id));
+ thread_id= 0;
+ if (dropped)
+ drop(thd);
+ pthread_cond_broadcast(&COND_finished);
+ should_free= flags & EVENT_FREE_WHEN_FINISHED;
+ VOID(pthread_mutex_unlock(&LOCK_running));
+ DBUG_RETURN(should_free);
+}
+
+
+/*
+ Kills a running event
+ SYNOPSIS
+ Event_timed::kill_thread()
+
+ RETURN VALUE
+ 0 OK
+ -1 EVEX_CANT_KILL
+ !0 Error
+*/
+
+int
+Event_timed::kill_thread(THD *thd)
+{
+ int ret= 0;
+ DBUG_ENTER("Event_timed::kill_thread");
+ pthread_mutex_lock(&LOCK_running);
+ DBUG_PRINT("info", ("thread_id=%lu", thread_id));
+
+ if (thread_id == thd->thread_id)
{
- DBUG_PRINT("info", ("%s exec no more. to drop=%d", name.str, dropped));
- if (dropped)
- drop(thd);
- VOID(pthread_mutex_unlock(&this->LOCK_running));
- delete this;
- DBUG_VOID_RETURN;
+ /*
+ We don't kill ourselves in cases like :
+ alter event e_43 do alter event e_43 do set @a = 4 because
+ we will never receive COND_finished.
+ */
+ DBUG_PRINT("info", ("It's not safe to kill ourselves in self altering queries"));
+ ret= EVEX_CANT_KILL;
}
- VOID(pthread_mutex_unlock(&this->LOCK_running));
- DBUG_VOID_RETURN;
+ else if (thread_id && !(ret= kill_one_thread(thd, thread_id, false)))
+ {
+ thd->enter_cond(&COND_finished, &LOCK_running, "Waiting for finished");
+ DBUG_PRINT("info", ("Waiting for COND_finished from thread %d", thread_id));
+ while (thread_id)
+ pthread_cond_wait(&COND_finished, &LOCK_running);
+
+ DBUG_PRINT("info", ("Got COND_finished"));
+ /* This will implicitly unlock LOCK_running. Hence we return before that */
+ thd->exit_cond("");
+
+ DBUG_RETURN(0);
+ }
+ else if (!thread_id && in_spawned_thread)
+ {
+ /*
+ Because the manager thread waits for the forked thread to update thread_id
+ this situation is impossible.
+ */
+ DBUG_ASSERT(0);
+ }
+ pthread_mutex_unlock(&LOCK_running);
+ DBUG_PRINT("exit", ("%d", ret));
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ Checks whether two events have the same name
+
+ SYNOPSIS
+ event_timed_name_equal()
+
+ RETURN VALUE
+ TRUE names are equal
+ FALSE names are not equal
+*/
+
+bool
+event_timed_name_equal(Event_timed *et, LEX_STRING *name)
+{
+ return !sortcmp_lex_string(et->name, *name, system_charset_info);
+}
+
+
+/*
+ Checks whether two events are in the same schema
+
+ SYNOPSIS
+ event_timed_db_equal()
+
+ RETURN VALUE
+ TRUE schemas are equal
+ FALSE schemas are not equal
+*/
+
+bool
+event_timed_db_equal(Event_timed *et, LEX_STRING *db)
+{
+ return !sortcmp_lex_string(et->dbname, *db, system_charset_info);
}
/*
- Unlocks the object after it has been locked with ::can_spawn_now_n_lock()
+ Checks whether two events have the same definer
+
+ SYNOPSIS
+ event_timed_definer_equal()
Returns
- 0 - ok
- 1 - not locked by this thread
+ TRUE definers are equal
+ FALSE definers are not equal
*/
-int
-Event_timed::spawn_unlock(THD *thd)
+bool
+event_timed_definer_equal(Event_timed *et, LEX_STRING *definer)
{
- int ret= 0;
- VOID(pthread_mutex_lock(&this->LOCK_running));
- if (!in_spawned_thread)
+ return !sortcmp_lex_string(et->definer, *definer, system_charset_info);
+}
+
+
+/*
+ Checks whether two events are equal by identifiers
+
+ SYNOPSIS
+ event_timed_identifier_equal()
+
+ RETURN VALUE
+ TRUE equal
+ FALSE not equal
+*/
+
+bool
+event_timed_identifier_equal(Event_timed *a, Event_timed *b)
+{
+ return event_timed_name_equal(a, &b->name) &&
+ event_timed_db_equal(a, &b->dbname) &&
+ event_timed_definer_equal(a, &b->definer);
+}
+
+
+/*
+ Switches the security context
+ SYNOPSIS
+ change_security_context()
+ thd Thread
+ user The user
+ host The host of the user
+ db The schema for which the security_ctx will be loaded
+ s_ctx Security context to load state into
+ backup Where to store the old context
+
+ RETURN VALUE
+ 0 - OK
+ 1 - Error (generates error too)
+*/
+
+bool
+change_security_context(THD *thd, LEX_STRING user, LEX_STRING host,
+ LEX_STRING db, Security_context *s_ctx,
+ Security_context **backup)
+{
+ DBUG_ENTER("change_security_context");
+ DBUG_PRINT("info",("%s@%s@%s", user.str, host.str, db.str));
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ s_ctx->init();
+ *backup= 0;
+ if (acl_getroot_no_password(s_ctx, user.str, host.str, host.str, db.str))
{
- if (locked_by_thread_id == thd->thread_id)
- {
- in_spawned_thread= FALSE;
- locked_by_thread_id= 0;
- }
- else
- {
- sql_print_error("A thread tries to unlock when he hasn't locked. "
- "thread_id=%ld locked by %ld",
- thd->thread_id, locked_by_thread_id);
- DBUG_ASSERT(0);
- ret= 1;
- }
+ my_error(ER_NO_SUCH_USER, MYF(0), user.str, host.str);
+ DBUG_RETURN(TRUE);
}
- VOID(pthread_mutex_unlock(&this->LOCK_running));
- return ret;
+ *backup= thd->security_ctx;
+ thd->security_ctx= s_ctx;
+#endif
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ Restores the security context
+ SYNOPSIS
+ restore_security_context()
+ thd - thread
+ backup - switch to this context
+*/
+
+void
+restore_security_context(THD *thd, Security_context *backup)
+{
+ DBUG_ENTER("restore_security_context");
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (backup)
+ thd->security_ctx= backup;
+#endif
+ DBUG_VOID_RETURN;
}
| Thread |
|---|
| • bk commit into 5.1 tree (andrey:1.2186) | ahristov | 25 May |