Commit b0739269 authored by unknown's avatar unknown
Browse files

Merge ahristov@bk-internal.mysql.com:/home/bk/mysql-5.1-new

into lmy004.:/work/mysql-5.1-bug17289

parents 6753b5fd 77970a98
Loading
Loading
Loading
Loading
+26 −1
Original line number Diff line number Diff line
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")
+33 −0
Original line number Diff line number Diff line
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;
+6 −0
Original line number Diff line number Diff line
@@ -203,6 +203,12 @@ class event_timed
    delete sphead;
    sphead= 0;
  }
protected:
  bool
  change_security_context(THD *thd, Security_context **backup);

  void
  restore_security_context(THD *thd, Security_context *backup);
};


+79 −22
Original line number Diff line number Diff line
@@ -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;
@@ -205,7 +207,10 @@ 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);
}
+80 −4
Original line number Diff line number Diff line
@@ -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;
  
  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 @@ event_timed::execute(THD *thd, MEM_ROOT *mem_root)
    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
Loading