From a378e8772b27ae1a3a0580d46cc9b0f14127df12 Mon Sep 17 00:00:00 2001
From: unknown <andrey@lmy004.>
Date: Fri, 20 Jan 2006 22:24:58 +0100
Subject: [PATCH] fix for bug#16431 (Events: An event which alters itself
 disappears) WL#1034 (Internal CRON)

mysql-test/r/events.result:
  add a test for to test bug #16431
mysql-test/t/events.test:
  results of new tests
sql/event.cc:
  - more debug info
  - pass info to evex_remove_from_cache() whether the operation
    was drop or alter. this fixes possible bug that may lead to dropping
    of an event when it's altered. also fix for bug#16431
sql/event_executor.cc:
  be more verbose and throw more errors
sql/event_timed.cc:
  - add ` around the names of the db and the event_name and not
  their concatenation. remove ; from the end - unneeded. this fixes bug #16431,
  which was failing because after some recursion the query was ending on ;;
  which is normally an error in the parser because that's the delimiter

  - more debug info
  - don't execute lex_end() two times when there's a parse error or thd->is_fatal_error
---
 mysql-test/r/events.result | 17 +++++++++++++++++
 mysql-test/t/events.test   | 10 ++++++++++
 sql/event.cc               | 18 ++++++++++++------
 sql/event_executor.cc      |  6 ++++++
 sql/event_timed.cc         | 28 +++++++++++++++++-----------
 5 files changed, 62 insertions(+), 17 deletions(-)

diff --git a/mysql-test/r/events.result b/mysql-test/r/events.result
index 4e1648de6b9..c3b94e580c2 100644
--- a/mysql-test/r/events.result
+++ b/mysql-test/r/events.result
@@ -12,6 +12,23 @@ alter event event3 rename to event2;
 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 event e_43 on schedule every 1 second do set @a = 5;
+set global event_scheduler = 1;
+select sleep(2);
+sleep(2)
+0
+alter event e_43 do alter event e_43 do set @a = 4;
+select sleep(3);
+sleep(3)
+0
+select db, name, body, status, interval_field, interval_value from mysql.event;
+db	name	body	status	interval_field	interval_value
+events_test	e_43	 set @a = 4	ENABLED	SECOND	1
+drop event e_43;
+select sleep(1);
+sleep(1)
+0
+set global event_scheduler = 0;
 create table t_event3 (a int, b float);
 drop event if exists event3;
 Warnings:
diff --git a/mysql-test/t/events.test b/mysql-test/t/events.test
index 64288f3b9a1..3f9445fc845 100644
--- a/mysql-test/t/events.test
+++ b/mysql-test/t/events.test
@@ -14,6 +14,16 @@ 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 event e_43 on schedule every 1 second do set @a = 5;
+set global event_scheduler = 1;
+select sleep(2);
+alter event e_43 do alter event e_43 do set @a = 4;
+select sleep(3);
+select db, name, body, status, interval_field, interval_value from mysql.event;
+drop event e_43;
+select sleep(1);
+set global event_scheduler = 0;
+
 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());
diff --git a/sql/event.cc b/sql/event.cc
index 6d62be903bd..cb1b2efad0a 100644
--- a/sql/event.cc
+++ b/sql/event.cc
@@ -237,8 +237,9 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
     DBUG_RETURN(EVEX_GET_FIELD_FAILED);
   }
   
-  DBUG_PRINT("info", ("dbname.len=%d",et->dbname.length));  
-  DBUG_PRINT("info", ("name.len=%d",et->name.length));  
+  DBUG_PRINT("info", ("dbname.len=[%s]",et->dbname.str));  
+  DBUG_PRINT("info", ("name.len=[%s]",et->name.str));  
+  DBUG_PRINT("info", ("body=[%s]",et->body.str));  
 
   if (table->field[field_num= EVEX_FIELD_DB]->
                   store(et->dbname.str, et->dbname.length, system_charset_info))
@@ -674,7 +675,8 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, bool use_lock)
 
 
 static int
-evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock)
+evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
+                       bool is_drop)
 {
   uint i;
 
@@ -697,14 +699,18 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock)
     {
       if (!et->is_running())
       {
+        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= true;
+        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
       goto done;
@@ -805,7 +811,7 @@ evex_update_event(THD *thd, event_timed *et, sp_name *new_name,
     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);
+  evex_remove_from_cache(&et->dbname, &et->name, false, false);
   if (et->status == MYSQL_EVENT_ENABLED)
   {
     if (new_name)
@@ -874,7 +880,7 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
 
   VOID(pthread_mutex_lock(&LOCK_evex_running));
   if (evex_is_running)
-    ret= evex_remove_from_cache(&et->dbname, &et->name, true);
+    ret= evex_remove_from_cache(&et->dbname, &et->name, true, true);
   VOID(pthread_mutex_unlock(&LOCK_evex_running));
 
 done:
diff --git a/sql/event_executor.cc b/sql/event_executor.cc
index dd426c32545..e655f5890b3 100644
--- a/sql/event_executor.cc
+++ b/sql/event_executor.cc
@@ -492,12 +492,18 @@ event_executor_worker(void *event_void)
     sql_print_information("    EVEX EXECUTED event %s.%s  [EXPR:%d]. RetCode=%d",
                           event->dbname.str, event->name.str,
                           (int) event->expression, ret);
+    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));
   }
   if ((event->flags & EVENT_EXEC_NO_MORE) || event->status==MYSQL_EVENT_DISABLED)
   {
+    DBUG_PRINT("event_executor_worker",
+               ("%s exec no more. to drop=%d",event->name.str, event->dropped));
     if (event->dropped)
       event->drop(thd);
     delete event;
diff --git a/sql/event_timed.cc b/sql/event_timed.cc
index cc8849364da..f17675c6ec5 100644
--- a/sql/event_timed.cc
+++ b/sql/event_timed.cc
@@ -806,16 +806,18 @@ event_timed::get_show_create_event(THD *thd, uint *length)
 {
   char *dst, *ret;
   uint len, tmp_len;
+  DBUG_ENTER("get_show_create_event");
+  DBUG_PRINT("ret_info",("body_len=[%d]body=[%s]", body.length, body.str));
 
-  len = strlen("CREATE EVENT `") + dbname.length + strlen(".") + name.length +
-        strlen("` ON SCHEDULE EVERY 5 MINUTE DO ") + body.length + strlen(";");
+  len = strlen("CREATE EVENT `") + dbname.length + strlen("`.`") + name.length +
+        strlen("` ON SCHEDULE EVERY 5 MINUTE DO ") + body.length;// + strlen(";");
   
   ret= dst= (char*) alloc_root(thd->mem_root, len + 1);
   memcpy(dst, "CREATE EVENT `", tmp_len= strlen("CREATE EVENT `"));
   dst+= tmp_len;
   memcpy(dst, dbname.str, tmp_len=dbname.length);
   dst+= tmp_len;
-  memcpy(dst, ".", tmp_len= strlen("."));
+  memcpy(dst, "`.`", tmp_len= strlen("`.`"));
   dst+= tmp_len;
   memcpy(dst, name.str, tmp_len= name.length);
   dst+= tmp_len;
@@ -825,13 +827,14 @@ event_timed::get_show_create_event(THD *thd, uint *length)
 
   memcpy(dst, body.str, tmp_len= body.length);
   dst+= tmp_len;
-  memcpy(dst, ";", 1);
-  ++dst;
+//  memcpy(dst, ";", 1);
+//  ++dst;
   *dst= '\0';
  
   *length= len;
-
-  return ret;
+  
+  DBUG_PRINT("ret_info",("len=%d",*length));
+  DBUG_RETURN(ret);
 }
 
 
@@ -944,8 +947,12 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
   lex.et_compile_phase= TRUE;
   if (yyparse((void *)thd) || thd->is_fatal_error)
   {
+    DBUG_PRINT("error", ("error during compile or thd->is_fatal_error=%d",
+                          thd->is_fatal_error));
     //  Free lex associated resources
     //  QQ: Do we really need all this stuff here ?
+    sql_print_error("error during compile of %s.%s or thd->is_fatal_error=%d",
+                    dbname.str, name.str, thd->is_fatal_error);
     if (lex.sphead)
     {
       if (&lex != thd->lex)
@@ -953,13 +960,10 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
       delete lex.sphead;
       lex.sphead= 0;
     }
-    // QQ: anything else ?
-    lex_end(&lex);
-    thd->lex= old_lex;
-
     ret= EVEX_COMPILE_ERROR;
     goto done;
   }
+  DBUG_PRINT("note", ("success compiling %s.%s", dbname.str, name.str));
   
   sphead= lex.et->sphead;
   sphead->m_db= dbname;
@@ -973,6 +977,8 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
   lex.et->free_sphead_on_delete= false;
   delete lex.et;
   lex_end(&lex);
+  DBUG_PRINT("note", ("return old data on its place. set back NAMES"));
+
   thd->lex= old_lex;
   thd->query= old_query;
   thd->query_length= old_query_len;
-- 
2.30.9