mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 10:14:19 +01:00
Merge ahristov@bk-internal.mysql.com:/home/bk/mysql-5.1-new
into lmy004.:/work/mysql-5.1-bug17289
This commit is contained in:
commit
b07392692c
6 changed files with 233 additions and 31 deletions
|
@ -1,5 +1,28 @@
|
|||
create database if not exists events_test;
|
||||
use events_test;
|
||||
CREATE USER pauline@localhost;
|
||||
CREATE DATABASE db_x;
|
||||
GRANT EVENT ON db_x.* TO pauline@localhost;
|
||||
USE db_x;
|
||||
CREATE TABLE x_table(a int);
|
||||
CREATE EVENT e_x1 ON SCHEDULE EVERY 1 SECOND DO DROP DATABASE db_x;
|
||||
CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SECOND DO DROP TABLE x_table;
|
||||
SHOW DATABASES LIKE 'db_x';
|
||||
Database (db_x)
|
||||
db_x
|
||||
SET GLOBAL event_scheduler=1;
|
||||
SHOW DATABASES LIKE 'db_x';
|
||||
Database (db_x)
|
||||
db_x
|
||||
SHOW TABLES FROM db_x;
|
||||
Tables_in_db_x
|
||||
x_table
|
||||
SET GLOBAL event_scheduler=0;
|
||||
DROP EVENT e_x1;
|
||||
DROP EVENT e_x2;
|
||||
DROP DATABASE db_x;
|
||||
DROP USER pauline@localhost;
|
||||
USE events_test;
|
||||
drop event if exists event1;
|
||||
Warnings:
|
||||
Note 1305 Event event1 does not exist
|
||||
|
@ -166,7 +189,7 @@ show processlist;
|
|||
Id User Host db Command Time State Info
|
||||
# root localhost events_test Query # NULL show processlist
|
||||
# event_scheduler NULL Connect # Sleeping NULL
|
||||
# root events_test Connect # User lock select get_lock("test_lock2", 20)
|
||||
# root localhost events_test Connect # User lock select get_lock("test_lock2", 20)
|
||||
"Release the mutex, the event worker should finish."
|
||||
select release_lock("test_lock2");
|
||||
release_lock("test_lock2")
|
||||
|
@ -184,6 +207,8 @@ set global event_scheduler=0;
|
|||
show processlist;
|
||||
Id User Host db Command Time State Info
|
||||
# root localhost events_test Query # NULL show processlist
|
||||
# event_scheduler 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,5 +1,38 @@
|
|||
create database if not exists events_test;
|
||||
use events_test;
|
||||
|
||||
#
|
||||
# START: BUG #17289 Events: missing privilege check for drop database
|
||||
#
|
||||
CREATE USER pauline@localhost;
|
||||
CREATE DATABASE db_x;
|
||||
GRANT EVENT ON db_x.* TO pauline@localhost;
|
||||
USE db_x;
|
||||
CREATE TABLE x_table(a int);
|
||||
connect (priv_conn,localhost,pauline,,db_x);
|
||||
CREATE EVENT e_x1 ON SCHEDULE EVERY 1 SECOND DO DROP DATABASE db_x;
|
||||
CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SECOND DO DROP TABLE x_table;
|
||||
connection default;
|
||||
SHOW DATABASES LIKE 'db_x';
|
||||
SET GLOBAL event_scheduler=1;
|
||||
--sleep 2
|
||||
SHOW DATABASES LIKE 'db_x';
|
||||
SHOW TABLES FROM db_x;
|
||||
SET GLOBAL event_scheduler=0;
|
||||
--sleep 1
|
||||
connection priv_conn;
|
||||
DROP EVENT e_x1;
|
||||
DROP EVENT e_x2;
|
||||
disconnect priv_conn;
|
||||
connection default;
|
||||
DROP DATABASE db_x;
|
||||
DROP USER pauline@localhost;
|
||||
USE events_test;
|
||||
--sleep 1
|
||||
#
|
||||
# END: BUG #17289 Events: missing privilege check for drop database
|
||||
#
|
||||
|
||||
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;
|
||||
|
|
|
@ -203,6 +203,12 @@ public:
|
|||
delete sphead;
|
||||
sphead= 0;
|
||||
}
|
||||
protected:
|
||||
bool
|
||||
change_security_context(THD *thd, Security_context **backup);
|
||||
|
||||
void
|
||||
restore_security_context(THD *thd, Security_context *backup);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@ static uint workers_count;
|
|||
static int
|
||||
evex_load_events_from_db(THD *thd);
|
||||
|
||||
|
||||
bool
|
||||
evex_print_warnings(THD *thd, event_timed *et);
|
||||
|
||||
/*
|
||||
TODO Andrey: Check for command line option whether to start
|
||||
|
@ -135,7 +136,8 @@ init_event_thread(THD* thd)
|
|||
{
|
||||
DBUG_ENTER("init_event_thread");
|
||||
thd->client_capabilities= 0;
|
||||
thd->security_ctx->skip_grants();
|
||||
thd->security_ctx->master_access= 0;
|
||||
thd->security_ctx->db_access= 0;
|
||||
thd->security_ctx->host= (char*)my_localhost;
|
||||
my_net_init(&thd->net, 0);
|
||||
thd->net.read_timeout = slave_net_timeout;
|
||||
|
@ -204,8 +206,11 @@ event_executor_main(void *arg)
|
|||
|
||||
if (init_event_thread(thd))
|
||||
goto err;
|
||||
|
||||
// make this thread invisible it has no vio -> show processlist won't see
|
||||
|
||||
/*
|
||||
make this thread visible it has no vio -> show processlist won't see it
|
||||
unless it's marked as system thread
|
||||
*/
|
||||
thd->system_thread= 1;
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_thread_count));
|
||||
|
@ -481,21 +486,8 @@ event_executor_worker(void *event_void)
|
|||
thd= current_thd;
|
||||
#endif
|
||||
|
||||
// thd->security_ctx->priv_host is char[MAX_HOSTNAME]
|
||||
|
||||
strxnmov(thd->security_ctx->priv_host, sizeof(thd->security_ctx->priv_host),
|
||||
event->definer_host.str, NullS);
|
||||
|
||||
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)))
|
||||
{
|
||||
int ret;
|
||||
DBUG_PRINT("info", (" EVEX EXECUTING event %s.%s [EXPR:%d]",
|
||||
event->dbname.str, event->name.str,(int) event->expression));
|
||||
sql_print_information(" EVEX EXECUTING event %s.%s [EXPR:%d]",
|
||||
event->dbname.str, event->name.str,(int) event->expression);
|
||||
|
||||
|
@ -507,10 +499,7 @@ event_executor_worker(void *event_void)
|
|||
if (ret == EVEX_COMPILE_ERROR)
|
||||
sql_print_information(" EVEX COMPILE ERROR for event %s.%s",
|
||||
event->dbname.str, event->name.str);
|
||||
|
||||
DBUG_PRINT("info", (" EVEX EXECUTED event %s.%s [EXPR:%d]. RetCode=%d",
|
||||
event->dbname.str, event->name.str,
|
||||
(int) event->expression, ret));
|
||||
evex_print_warnings(thd, event);
|
||||
}
|
||||
if ((event->flags & EVENT_EXEC_NO_MORE) || event->status==MYSQL_EVENT_DISABLED)
|
||||
{
|
||||
|
@ -521,7 +510,6 @@ event_executor_worker(void *event_void)
|
|||
delete event;
|
||||
}
|
||||
|
||||
thd->db= 0;
|
||||
|
||||
err:
|
||||
VOID(pthread_mutex_lock(&LOCK_thread_count));
|
||||
|
@ -666,3 +654,72 @@ bool sys_var_event_executor::update(THD *thd, set_var *var)
|
|||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
extern LEX_STRING warning_level_names[];
|
||||
|
||||
typedef void (*sql_print_xxx_func)(const char *format, ...);
|
||||
static sql_print_xxx_func sql_print_xxx_handlers[3] =
|
||||
{
|
||||
sql_print_information,
|
||||
sql_print_warning,
|
||||
sql_print_error
|
||||
};
|
||||
|
||||
/*
|
||||
Prints the stack of infos, warnings, errors from thd to
|
||||
the console so it can be fetched by the logs-into-tables and
|
||||
checked later.
|
||||
|
||||
Synopsis
|
||||
evex_print_warnings
|
||||
thd - thread used during the execution of the event
|
||||
et - the event itself
|
||||
|
||||
Returns
|
||||
0 - OK (always)
|
||||
|
||||
*/
|
||||
|
||||
bool
|
||||
evex_print_warnings(THD *thd, event_timed *et)
|
||||
{
|
||||
MYSQL_ERROR *err;
|
||||
DBUG_ENTER("evex_show_warnings");
|
||||
char msg_buf[1024];
|
||||
char prefix_buf[512];
|
||||
String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info);
|
||||
prefix.length(0);
|
||||
|
||||
List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
|
||||
while ((err= it++))
|
||||
{
|
||||
String err_msg(msg_buf, sizeof(msg_buf), system_charset_info);
|
||||
err_msg.length(0);// set it to 0 or we start adding at the end
|
||||
if (!prefix.length())
|
||||
{
|
||||
prefix.append("SCHEDULER: [");
|
||||
|
||||
append_identifier(thd,&prefix,et->definer_user.str,et->definer_user.length);
|
||||
prefix.append('@');
|
||||
append_identifier(thd,&prefix,et->definer_host.str,et->definer_host.length);
|
||||
prefix.append("][", 2);
|
||||
append_identifier(thd,&prefix, et->dbname.str, et->dbname.length);
|
||||
prefix.append('.');
|
||||
append_identifier(thd,&prefix, et->name.str, et->name.length);
|
||||
prefix.append("] ", 2);
|
||||
}
|
||||
|
||||
err_msg.append(prefix);
|
||||
err_msg.append('[');
|
||||
err_msg.append(warning_level_names[err->level].str,
|
||||
warning_level_names[err->level].length, system_charset_info);
|
||||
err_msg.append("] [");
|
||||
err_msg.append(err->msg, strlen(err->msg), system_charset_info);
|
||||
err_msg.append("]");
|
||||
DBUG_ASSERT(err->level < 3);
|
||||
(sql_print_xxx_handlers[err->level])("%*s", err_msg.length(), err_msg.c_ptr());
|
||||
// sql_print_information("%*s", err_msg.length(), err_msg.c_ptr());
|
||||
}
|
||||
|
||||
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
|
|
@ -982,12 +982,13 @@ event_timed::get_show_create_event(THD *thd, uint32 *length)
|
|||
Executes the event (the underlying sp_head object);
|
||||
|
||||
SYNOPSIS
|
||||
evex_fill_row()
|
||||
event_timed::execute()
|
||||
thd THD
|
||||
mem_root If != NULL use it to compile the event on it
|
||||
|
||||
Returns
|
||||
0 - success
|
||||
-99 - No access to the database.
|
||||
-100 - event in execution (parallel execution is impossible)
|
||||
others - retcodes of sp_head::execute_procedure()
|
||||
|
||||
|
@ -996,10 +997,12 @@ event_timed::get_show_create_event(THD *thd, uint32 *length)
|
|||
int
|
||||
event_timed::execute(THD *thd, MEM_ROOT *mem_root)
|
||||
{
|
||||
List<Item> empty_item_list;
|
||||
Security_context *save_ctx;
|
||||
int ret= 0;
|
||||
|
||||
DBUG_ENTER("event_timed::execute");
|
||||
DBUG_PRINT("info", (" EVEX EXECUTING event %s.%s [EXPR:%d]",
|
||||
dbname.str, name.str, (int) expression));
|
||||
|
||||
VOID(pthread_mutex_lock(&this->LOCK_running));
|
||||
if (running)
|
||||
|
@ -1011,12 +1014,35 @@ event_timed::execute(THD *thd, MEM_ROOT *mem_root)
|
|||
VOID(pthread_mutex_unlock(&this->LOCK_running));
|
||||
|
||||
// TODO Andrey : make this as member variable and delete in destructor
|
||||
empty_item_list.empty();
|
||||
|
||||
if (!sphead && (ret= compile(thd, mem_root)))
|
||||
goto done;
|
||||
|
||||
ret= sphead->execute_procedure(thd, &empty_item_list);
|
||||
thd->db= dbname.str;
|
||||
thd->db_length= dbname.length;
|
||||
|
||||
DBUG_PRINT("info", ("master_access=%d db_access=%d",
|
||||
thd->security_ctx->master_access, thd->security_ctx->db_access));
|
||||
change_security_context(thd, &save_ctx);
|
||||
DBUG_PRINT("info", ("master_access=%d db_access=%d",
|
||||
thd->security_ctx->master_access, thd->security_ctx->db_access));
|
||||
// if (mysql_change_db(thd, dbname.str, 0))
|
||||
if (!check_access(thd, EVENT_ACL,dbname.str, 0, 0, 0,is_schema_db(dbname.str)))
|
||||
{
|
||||
List<Item> empty_item_list;
|
||||
empty_item_list.empty();
|
||||
ret= sphead->execute_procedure(thd, &empty_item_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_PRINT("error", ("%s@%s has no rights on %s", definer_user.str,
|
||||
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));
|
||||
thd->db= 0;
|
||||
|
||||
VOID(pthread_mutex_lock(&this->LOCK_running));
|
||||
running= false;
|
||||
|
@ -1029,11 +1055,61 @@ done:
|
|||
delete sphead;
|
||||
sphead= 0;
|
||||
}
|
||||
DBUG_PRINT("info", (" EVEX EXECUTED event %s.%s [EXPR:%d]. RetCode=%d",
|
||||
dbname.str, name.str, (int) expression, ret));
|
||||
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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 **backup)
|
||||
{
|
||||
DBUG_ENTER("event_timed::change_security_context");
|
||||
DBUG_PRINT("info",("%s@%s@%s",definer_user.str,definer_host.str, dbname.str));
|
||||
*backup= 0;
|
||||
if (acl_getroot_no_password(&sphead->m_security_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= &sphead->m_security_ctx;
|
||||
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Restores the security context
|
||||
Synopsis
|
||||
event_timed::restore_security_context()
|
||||
thd - thread
|
||||
backup - switch to this context
|
||||
*/
|
||||
|
||||
void
|
||||
event_timed::restore_security_context(THD *thd, Security_context *backup)
|
||||
{
|
||||
DBUG_ENTER("event_timed::change_security_context");
|
||||
if (backup)
|
||||
thd->security_ctx= backup;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Returns
|
||||
0 - Success
|
||||
|
|
|
@ -211,8 +211,13 @@ void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
|
|||
TRUE Error sending data to client
|
||||
*/
|
||||
|
||||
static const char *warning_level_names[]= {"Note", "Warning", "Error", "?"};
|
||||
static int warning_level_length[]= { 4, 7, 5, 1 };
|
||||
LEX_STRING warning_level_names[]=
|
||||
{
|
||||
{(char*) STRING_WITH_LEN("Note")},
|
||||
{(char*) STRING_WITH_LEN("Warning")},
|
||||
{(char*) STRING_WITH_LEN("Error")},
|
||||
{(char*) STRING_WITH_LEN("?")}
|
||||
};
|
||||
|
||||
bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
|
||||
{
|
||||
|
@ -246,8 +251,8 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
|
|||
if (idx > unit->select_limit_cnt)
|
||||
break;
|
||||
protocol->prepare_for_resend();
|
||||
protocol->store(warning_level_names[err->level],
|
||||
warning_level_length[err->level], system_charset_info);
|
||||
protocol->store(warning_level_names[err->level].str,
|
||||
warning_level_names[err->level].length, system_charset_info);
|
||||
protocol->store((uint32) err->code);
|
||||
protocol->store(err->msg, strlen(err->msg), system_charset_info);
|
||||
if (protocol->write())
|
||||
|
|
Loading…
Add table
Reference in a new issue