Commit 48405ec7 authored by unknown's avatar unknown

WL#1034 update

- fix EVENT_ACL problem that GRANT ALL on some_db.* to someone@somewhere did not get to mysql.db
- fix crash when the following is executed :
  CREATE EVENT P() CREATE EVENT E ON SCHEDULER 1 SECOND DO ROLLBACK;
  (creation works as well as calling P() which creates the event).


mysql-test/lib/init_db.sql:
  - fix init_db.sql so add Event_priv to the database privs, many tests failed because of that
    ommision
  - remove the quotes from the column names
mysql-test/t/events.test:
  - fix the small test, don't create own db
scripts/mysql_fix_privilege_tables.sql:
  - fix that
sql/event.cc:
  - be defensive and don't crash if outside has already has opened some table
sql/event_executor.cc:
  - show in SHOW PROCESSLIST - "event_scheduler" as name of the user of the main thread
  - use "localhost" as the host where event_scheduler comes from
  - comment out some debug info, fix other debug info
sql/event_timed.cc:
  - enable EVENT creation inside SP. sphead from lex->sphead goes to et->sphead. it's there only
    if we compile the event. OTOH when doing 
    CREATE PROCEDURE PROC() CREATE EVENT SOME_EV ON SCHEDULE EVERY 1 SECOND DO ROLLBACK;
    I have only to get the body of the event which is anonymous SP. Before it being "compiled"
    but then freed without being used because a bit later it is compiled one more time before
    being put in the events cache. So it was good that the memory structures weren't reused but
    scrapped out. Now lex->sphead is not needed during event creation but only where the event's
    body starts and where it ends so to be able at later stage to compile this anonymous SP (the
    body of the event).
sql/sp_head.cc:
  - copy over a fix to a crash
sql/sql_acl.h:
  - fix privileges.
    There was _NO_ documentation about that. Another CHUNK had to be created to so EVENT_ACL gets shifted to
    it's place in the db table. So how this is calculated? EVENT_ACL is 1 << 26. Remember 26, see which poistion
    in the db table is EVENT_ACL, it's 17, counted from 0. 26 - 17 = 9, then shift it with 9.
    CHUNKS are created because in some cases some privileges are in chunks and they are shifted at once. There are
    few chunks of such privileges which has to be shifted to get to exactly the structure of mysql.db table.
sql/sql_parse.cc:
  - ok, we don't care anymore about lex->sphead because our sphead is lex->et->sphead
sql/sql_yacc.yy:
  - bail out if new event_timed returns 0x0
  - enable creation of an event inside a SP
    CREATE PROCEDURE P() CREATE EVENT E ON SCHEDULE EVERY 1 SECOND DO SELECT 1;
parent b67555d5
......@@ -22,6 +22,7 @@ CREATE TABLE db (
Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
PRIMARY KEY Host (Host,Db,User),
KEY User (User)
) engine=MyISAM
......@@ -29,8 +30,8 @@ CHARACTER SET utf8 COLLATE utf8_bin
comment='Database privileges';
INSERT INTO db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N');
INSERT INTO db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N');
INSERT INTO db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y');
INSERT INTO db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y');
CREATE TABLE host (
......@@ -570,26 +571,26 @@ CREATE TABLE proc (
CREATE TABLE event (
'db' VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
'name' VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
'body' longblob NOT NULL,
'definer' VARCHAR(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
'execute_at' DATETIME default NULL,
'transient_expression' int(11) default NULL,
'interval_type' ENUM('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK',
db VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
name VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
body longblob NOT NULL,
definer VARCHAR(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
execute_at DATETIME default NULL,
transient_expression int(11) default NULL,
interval_type 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 default '0000-00-00 00:00:00',
'modified' TIMESTAMP NOT NULL default '0000-00-00 00:00:00',
'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 ('db','name')
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 (db, name)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events';
use test;
drop event if exists event1;
Warnings:
Note 1305 Event event1 does not exist
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;
alter event event2 disable;
drop event event2;
create event event2 on schedule every 2 second starts now() ends date_add(now(), interval 5 hour) comment "some" DO begin end;
drop event event2;
create table t_event3 (a int, b float);
drop event if exists event3;
Warnings:
Note 1305 Event event3 does not exist
create event event3 on schedule every 50 + 10 minute starts date_add("20010101", interval 5 minute) ends date_add("20151010", interval 5 day) comment "portokala_comment" DO insert into t_event3 values (unix_timestamp(), rand());
set max_allowed_packet=128000000;
select count(*) from t_event3;
count(*)
0
drop event event3;
drop table t_event3;
create database events_test;
use events_test;
use test;
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;
......@@ -13,7 +12,6 @@ create table t_event3 (a int, b float);
drop event if exists event3;
create event event3 on schedule every 50 + 10 minute starts date_add("20010101", interval 5 minute) ends date_add("20151010", interval 5 day) comment "portokala_comment" DO insert into t_event3 values (unix_timestamp(), rand());
set max_allowed_packet=128000000;
select sha1(space(9999999));
select count(*) from t_event3;
drop event event3;
drop database events_test;
drop table t_event3;
......@@ -562,5 +562,6 @@ CREATE TABLE event (
# EVENT privilege
#
ALTER TABLE mysql.user add Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Create_user_priv;
ALTER TABLE mysql.db add Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL;
ALTER TABLE mysql.user add Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL AFTER Create_user_priv;
ALTER TABLE mysql.db add Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL;
......@@ -652,6 +652,7 @@ 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));
......@@ -659,10 +660,12 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, bool use_lock)
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
if ((ret= db_find_event(thd, spn, &ett, NULL)))
goto done;
thd->restore_backup_open_tables_state(&backup);
/*
allocate on evex_mem_root. if you call without evex_mem_root
then sphead will not be cleared!
......
......@@ -30,7 +30,7 @@
#define DBUG_FAULTY_THR2
extern ulong thread_created;
extern const char *my_localhost;
pthread_mutex_t LOCK_event_arrays,
LOCK_workers_count,
......@@ -125,6 +125,7 @@ init_event_thread(THD* thd)
DBUG_ENTER("init_event_thread");
thd->client_capabilities= 0;
thd->security_ctx->skip_grants();
thd->security_ctx->host= (char*)my_localhost;
my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout;
thd->slave_thread= 0;
......@@ -211,6 +212,7 @@ event_executor_main(void *arg)
if (evex_load_events_from_db(thd))
goto err;
thd->security_ctx->user= my_strdup("event_scheduler", MYF(0));
THD_CHECK_SENTRY(thd);
/* Read queries from the IO/THREAD until this thread is killed */
evex_main_thread_id= thd->thread_id;
......@@ -254,8 +256,8 @@ event_executor_main(void *arg)
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
if (t2sleep > 0)
{
sql_print_information("Sleeping for %d seconds.", t2sleep);
printf("\nWHEN=%llu NOW=%llu\n", TIME_to_ulonglong_datetime(&et->execute_at), TIME_to_ulonglong_datetime(&time_now));
// sql_print_information("Sleeping for %d seconds.", t2sleep);
// printf("\nWHEN=%llu NOW=%llu\n", TIME_to_ulonglong_datetime(&et->execute_at), TIME_to_ulonglong_datetime(&time_now));
/*
We sleep t2sleep seconds but we check every second whether this thread
has been killed, or there is new candidate
......@@ -264,7 +266,7 @@ event_executor_main(void *arg)
evex_queue_num_elements(EVEX_EQ_NAME) &&
(evex_queue_first_element(&EVEX_EQ_NAME, event_timed*) == et))
my_sleep(1000000);
sql_print_information("Finished sleeping");
// sql_print_information("Finished sleeping");
}
if (!event_executor_running_global_var)
continue;
......@@ -297,9 +299,9 @@ event_executor_main(void *arg)
pthread_t th;
DBUG_PRINT("info", (" Spawning a thread %d", ++iter_num));
sql_print_information(" Spawning a thread %d", ++iter_num);
// sql_print_information(" Spawning a thread %d", ++iter_num);
#ifndef DBUG_FAULTY_THR
sql_print_information(" Thread is not debuggable!");
// sql_print_information(" Thread is not debuggable!");
if (pthread_create(&th, NULL, event_executor_worker, (void*)et))
{
sql_print_error("Problem while trying to create a thread");
......@@ -442,20 +444,18 @@ event_executor_worker(void *event_void)
strxnmov(thd->security_ctx->priv_host, sizeof(thd->security_ctx->priv_host),
event->definer_host.str, NullS);
thd->security_ctx->priv_user= event->definer_user.str;
thd->security_ctx->user= thd->security_ctx->priv_user= my_strdup(event->definer_user.str, MYF(0));
thd->db= event->dbname.str;
if (!check_access(thd, EVENT_ACL, event->dbname.str, 0, 0, 0,
is_schema_db(event->dbname.str)))
{
char exec_time[200];
int ret;
my_TIME_to_str(&event->execute_at, exec_time);
DBUG_PRINT("info", (" EVEX EXECUTING event for event %s.%s [EXPR:%d][EXECUTE_AT:%s]", event->dbname.str, event->name.str,(int) event->expression, exec_time));
sql_print_information(" EVEX EXECUTING event for event %s.%s [EXPR:%d][EXECUTE_AT:%s]", event->dbname.str, event->name.str,(int) event->expression, exec_time);
DBUG_PRINT("info", (" EVEX EXECUTING event for event %s.%s [EXPR:%d]", event->dbname.str, event->name.str,(int) event->expression));
sql_print_information(" EVEX EXECUTING event for event %s.%s [EXPR:%d]", event->dbname.str, event->name.str,(int) event->expression);
ret= event->execute(thd, &worker_mem_root);
sql_print_information(" EVEX EXECUTED event for event %s.%s [EXPR:%d][EXECUTE_AT:%s]. RetCode=%d", event->dbname.str, event->name.str,(int) event->expression, exec_time, ret);
DBUG_PRINT("info", (" EVEX EXECUTED event for event %s.%s [EXPR:%d][EXECUTE_AT:%s]", event->dbname.str, event->name.str,(int) event->expression, exec_time));
sql_print_information(" EVEX EXECUTED event for event %s.%s [EXPR:%d]. RetCode=%d", event->dbname.str, event->name.str,(int) event->expression, ret);
DBUG_PRINT("info", (" EVEX EXECUTED event for event %s.%s [EXPR:%d]. RetCode=%d", event->dbname.str, event->name.str,(int) event->expression, ret));
}
thd->db= 0;
......@@ -505,6 +505,7 @@ evex_load_events_from_db(THD *thd)
READ_RECORD read_record_info;
MYSQL_LOCK *lock;
int ret= -1;
uint count= 0;
DBUG_ENTER("evex_load_events_from_db");
......@@ -555,6 +556,7 @@ evex_load_events_from_db(THD *thd)
evex_queue_insert(&EVEX_EQ_NAME, (EVEX_PTOQEL) et);
DBUG_PRINT("evex_load_events_from_db", ("%p %*s",
et, et->name.length,et->name.str));
count++;
}
ret= 0;
......@@ -566,8 +568,8 @@ evex_load_events_from_db(THD *thd)
thd->version--; // Force close to free memory
close_thread_tables(thd);
DBUG_PRINT("info", ("Finishing with status code %d", ret));
sql_print_information("Scheduler loaded %d events", count);
DBUG_PRINT("info", ("Finishing with status code %d. Loaded %d events", ret, count));
DBUG_RETURN(ret);
}
......
......@@ -807,7 +807,6 @@ event_timed::get_show_create_event(THD *thd, uint *length)
*length= len;
sql_print_information("%d %d[%s]", len, dst-ret, ret);
return ret;
}
......@@ -938,7 +937,7 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
goto done;
}
sphead= lex.sphead;
sphead= lex.et->sphead;
sphead->m_db= dbname;
//copy also chistics since they will vanish otherwise we get 0x0 pointer
// Todo : Handle sql_mode !!
......@@ -947,6 +946,7 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
sphead->optimize();
ret= 0;
done:
lex.et->free_sphead_on_delete= false;
delete lex.et;
lex_end(&lex);
thd->lex= old_lex;
......
......@@ -960,8 +960,12 @@ int sp_head::execute(THD *thd)
m_first_instance->m_first_free_instance= m_next_cached_sp;
DBUG_PRINT("info", ("first free for 0x%lx ++: 0x%lx->0x%lx, level: %lu, flags %x",
(ulong)m_first_instance, this, m_next_cached_sp,
m_next_cached_sp->m_recursion_level,
m_next_cached_sp->m_flags));
(m_next_cached_sp ?
m_next_cached_sp->m_recursion_level :
0),
(m_next_cached_sp ?
m_next_cached_sp->m_flags :
0)));
/*
Check that if there are not any instances after this one then
pointer to the last instance points on this instance or if there are
......
......@@ -97,17 +97,20 @@
#define DB_CHUNK3 (CREATE_VIEW_ACL | SHOW_VIEW_ACL | \
CREATE_PROC_ACL | ALTER_PROC_ACL )
#define DB_CHUNK4 (EXECUTE_ACL)
#define DB_CHUNK5 (EVENT_ACL)
#define fix_rights_for_db(A) (((A) & DB_CHUNK0) | \
(((A) << 4) & DB_CHUNK1) | \
(((A) << 6) & DB_CHUNK2) | \
(((A) << 9) & DB_CHUNK3) | \
(((A) << 2) & DB_CHUNK4))
(((A) << 2) & DB_CHUNK4))| \
(((A) << 9) & DB_CHUNK5)
#define get_rights_for_db(A) (((A) & DB_CHUNK0) | \
(((A) & DB_CHUNK1) >> 4) | \
(((A) & DB_CHUNK2) >> 6) | \
(((A) & DB_CHUNK3) >> 9) | \
(((A) & DB_CHUNK4) >> 2))
(((A) & DB_CHUNK4) >> 2))| \
(((A) & DB_CHUNK5) >> 9)
#define TBL_CHUNK0 DB_CHUNK0
#define TBL_CHUNK1 DB_CHUNK1
#define TBL_CHUNK2 (CREATE_VIEW_ACL | SHOW_VIEW_ACL)
......
......@@ -3704,10 +3704,9 @@ mysql_execute_command(THD *thd)
/* lex->unit.cleanup() is called outside, no need to call it here */
} while (0);
lex->et->free_sphead_on_delete= true;
delete lex->et;
delete lex->sphead;
lex->et= 0;
lex->sphead= 0;
break;
}
case SQLCOM_SHOW_CREATE_EVENT:
......@@ -5658,6 +5657,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
}
if (thd->lex->et)
{
thd->lex->et->free_sphead_on_delete= true;
delete thd->lex->et;
thd->lex->et= NULL;
}
......@@ -5698,6 +5698,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
}
if (thd->lex->et)
{
thd->lex->et->free_sphead_on_delete= true;
delete thd->lex->et;
thd->lex->et= NULL;
}
......
......@@ -109,6 +109,7 @@ inline Item *is_truth_value(Item *A, bool v1, bool v2)
struct { int vars, conds, hndlrs, curs; } spblock;
sp_name *spname;
struct st_lex *lex;
sp_head *sphead;
}
%{
......@@ -1345,8 +1346,6 @@ create:
if (!lex->et_compile_phase)
lex->et->init_name(YYTHD, $4);
lex->sphead= 0;//defensive programming
}
ON SCHEDULE_SYM ev_schedule_time
ev_on_completion
......@@ -1482,33 +1481,46 @@ ev_sql_stmt:
{
LEX *lex= Lex;
sp_head *sp;
if (!(sp= new sp_head()))
YYABORT;
$<sphead>$= lex->sphead;
if (!lex->sphead)
{
if (!(sp= new sp_head()))
YYABORT;
sp->reset_thd_mem_root(YYTHD);
sp->init(lex);
sp->reset_thd_mem_root(YYTHD);
sp->init(lex);
sp->m_type= TYPE_ENUM_PROCEDURE;
lex->sphead= sp;
sp->m_type= TYPE_ENUM_PROCEDURE;
lex->sphead= sp;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics;
lex->sphead->m_body_begin= lex->ptr;
lex->sphead->m_body_begin= lex->ptr;
}
if (!lex->et_compile_phase)
lex->et->body_begin= lex->ptr;
}
ev_sql_stmt_inner
{
LEX *lex=Lex;
sp_head *sp= lex->sphead;
// return back to the original memory root ASAP
sp->init_strings(YYTHD, lex, NULL);
sp->restore_thd_mem_root(YYTHD);
if (!$<sphead>1)
{
sp_head *sp= lex->sphead;
// return back to the original memory root ASAP
sp->init_strings(YYTHD, lex, NULL);
sp->restore_thd_mem_root(YYTHD);
lex->sp_chistics.suid= SP_IS_SUID;//always the definer!
lex->sp_chistics.suid= SP_IS_SUID;//always the definer!
lex->et->sphead= lex->sphead;
lex->sphead= NULL;
}
if (!lex->et_compile_phase)
{
lex->et->init_body(YYTHD);
......@@ -4223,7 +4235,8 @@ alter:
}
lex->spname= 0;//defensive programming
et= new event_timed();// implicitly calls event_timed::init()
if (!(et= new event_timed()))// implicitly calls event_timed::init()
YYABORT;
lex->et = et;
et->init_name(YYTHD, $3);
......@@ -4235,11 +4248,6 @@ alter:
$<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
/*
defensive. in sql_parse.cc it is checked whether is not null
and then deleted
*/
lex->sphead= 0;
}
ev_on_schedule
ev_rename_to
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment