List:Commits« Previous MessageNext Message »
From:ahristov Date:June 28 2006 3:54pm
Subject:bk commit into 5.1 tree (andrey:1.2222)
View as plain text  
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.2222 06/06/28 15:54:09 andrey@lmy004. +10 -0
  Merge

  sql/sql_show.cc
    1.355 06/06/28 15:54:07 andrey@lmy004. +0 -0
    SCCS merged

  sql/sql_yacc.yy
    1.485 06/06/28 15:50:49 andrey@lmy004. +0 -0
    Auto merged

  sql/sql_parse.cc
    1.566 06/06/28 15:50:49 andrey@lmy004. +0 -0
    Auto merged

  sql/sql_lex.h
    1.235 06/06/28 15:50:48 andrey@lmy004. +0 -0
    Auto merged

  sql/sql_class.h
    1.305 06/06/28 15:50:48 andrey@lmy004. +0 -0
    Auto merged

  sql/sql_class.cc
    1.271 06/06/28 15:50:48 andrey@lmy004. +0 -0
    Auto merged

  sql/set_var.cc
    1.179 06/06/28 15:50:48 andrey@lmy004. +0 -0
    Auto merged

  sql/mysqld.cc
    1.565 06/06/28 15:50:48 andrey@lmy004. +0 -0
    Auto merged

  sql/events.cc
    1.46 06/06/28 15:50:47 andrey@lmy004. +0 -0
    Auto merged

  sql/CMakeLists.txt
    1.24 06/06/28 15:50:47 andrey@lmy004. +0 -0
    Auto merged

# 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-runtime-wl3337/RESYNC

--- 1.564/sql/mysqld.cc	2006-06-26 16:44:37 +02:00
+++ 1.565/sql/mysqld.cc	2006-06-28 15:50:48 +02:00
@@ -883,7 +883,7 @@ static void close_connections(void)
   }
   (void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
 
-  Events::shutdown();
+  Events::get_instance()->deinit();
   end_slave();
 
   if (thread_count)
@@ -1321,7 +1321,7 @@ static void clean_up_mutexes()
   (void) pthread_mutex_destroy(&LOCK_bytes_sent);
   (void) pthread_mutex_destroy(&LOCK_bytes_received);
   (void) pthread_mutex_destroy(&LOCK_user_conn);
-  Events::destroy_mutexes();
+  Events::get_instance()->destroy_mutexes();
 #ifdef HAVE_OPENSSL
   (void) pthread_mutex_destroy(&LOCK_des_key_file);
 #ifndef HAVE_YASSL
@@ -2884,7 +2884,7 @@ static int init_thread_environment()
   (void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST);
   (void) pthread_cond_init(&COND_server_started,NULL);
   sp_cache_init();
-  Events::init_mutexes();
+  Events::get_instance()->init_mutexes();
   /* Parameter for threads created for connections */
   (void) pthread_attr_init(&connection_attrib);
   (void) pthread_attr_setdetachstate(&connection_attrib,
@@ -3673,7 +3673,7 @@ we force server id to 2, but this MySQL 
 
   if (!opt_noacl)
   {
-    Events::init();
+    Events::get_instance()->init();
   }
 #if defined(__NT__) || defined(HAVE_SMEM)
   handle_connections_methods();

--- 1.270/sql/sql_class.cc	2006-06-26 11:26:18 +02:00
+++ 1.271/sql/sql_class.cc	2006-06-28 15:50:48 +02:00
@@ -2073,6 +2073,63 @@ bool Security_context::set_user(char *us
   return user == 0;
 }
 
+/*
+  Switches the security context
+  SYNOPSIS
+    THD::change_security_context()
+      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
+    FALSE  OK
+    TRUE   Error (generates error too)
+*/
+
+bool
+THD::change_security_context(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))
+  {
+    my_error(ER_NO_SUCH_USER, MYF(0), user.str, host.str);
+    DBUG_RETURN(TRUE);
+  }
+  *backup= security_ctx;
+  security_ctx= s_ctx;
+#endif
+  DBUG_RETURN(FALSE);
+}
+
+
+/*
+  Restores the security context
+  SYNOPSIS
+    restore_security_context()
+      thd     Thread
+      backup  Context to switch to
+*/
+
+void
+THD::restore_security_context(Security_context *backup)
+{
+  DBUG_ENTER("restore_security_context");
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+  if (backup)
+    security_ctx= backup;
+#endif
+  DBUG_VOID_RETURN;
+}
+
+
 /****************************************************************************
   Handling of open and locked tables states.
 

--- 1.304/sql/sql_class.h	2006-06-23 02:36:11 +02:00
+++ 1.305/sql/sql_class.h	2006-06-28 15:50:48 +02:00
@@ -868,6 +868,14 @@ public:
   char   *db, *catalog;
   Security_context main_security_ctx;
   Security_context *security_ctx;
+  
+  bool
+  change_security_context(LEX_STRING user, LEX_STRING host,
+                          LEX_STRING db, Security_context *s_ctx,
+                          Security_context **backup);  
+
+  void
+  restore_security_context(Security_context *backup);
 
   /* remote (peer) port */
   uint16 peer_port;

--- 1.234/sql/sql_lex.h	2006-06-20 12:20:28 +02:00
+++ 1.235/sql/sql_lex.h	2006-06-28 15:50:48 +02:00
@@ -28,6 +28,7 @@ class sp_pcontext;
 class st_alter_tablespace;
 class partition_info;
 class Event_timed;
+class Event_parse_data;
 
 #ifdef MYSQL_SERVER
 /*
@@ -1017,6 +1018,7 @@ typedef struct st_lex : public Query_tab
   st_sp_chistics sp_chistics;
 
   Event_timed *et;
+  Event_parse_data *event_parse_data;
   bool et_compile_phase;
 
   bool only_view;       /* used for SHOW CREATE TABLE/VIEW */

--- 1.565/sql/sql_parse.cc	2006-06-26 16:47:24 +02:00
+++ 1.566/sql/sql_parse.cc	2006-06-28 15:50:49 +02:00
@@ -27,7 +27,7 @@
 #include "sp.h"
 #include "sp_cache.h"
 #include "events.h"
-#include "event_timed.h"
+#include "event_data_objects.h"
 
 #ifdef HAVE_OPENSSL
 /*
@@ -3831,7 +3831,6 @@ end_with_restore_list:
   }
   case SQLCOM_CREATE_EVENT:
   case SQLCOM_ALTER_EVENT:
-  case SQLCOM_DROP_EVENT:
   {
     uint rows_affected= 1;
     DBUG_ASSERT(lex->et);
@@ -3860,17 +3859,15 @@ 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);
+        res= Events::get_instance()->
+                  create_event(thd, lex->et, lex->event_parse_data,
+                               (uint) lex->create_info.options, &rows_affected);
         break;
       case SQLCOM_ALTER_EVENT:
-        res= Events::update_event(thd, lex->et, lex->spname,
-                                  &rows_affected);
+        res= Events::get_instance()->
+                  update_event(thd, lex->et, lex->event_parse_data,
+                               lex->spname, &rows_affected);
         break;
-      case SQLCOM_DROP_EVENT:
-        res= Events::drop_event(thd, lex->et, lex->drop_if_exists,
-                                &rows_affected);
       default:;
       }
       DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
@@ -3889,10 +3886,10 @@ end_with_restore_list:
     
     break;
   }
+  case SQLCOM_DROP_EVENT:
   case SQLCOM_SHOW_CREATE_EVENT:
   {
     DBUG_ASSERT(lex->spname);
-    DBUG_ASSERT(lex->et);
     if (! lex->spname->m_db.str)
     {
       my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
@@ -3906,15 +3903,31 @@ end_with_restore_list:
     if (lex->spname->m_name.length > NAME_LEN)
     {
       my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
+      /* this jumps to the end of the function and skips own messaging */
       goto error;
     }
-    res= Events::show_create_event(thd, lex->spname);
+
+    if (lex->sql_command == SQLCOM_SHOW_CREATE_EVENT)
+      res= Events::get_instance()->show_create_event(thd, lex->spname);
+    else
+    {
+      uint rows_affected= 1;
+      if (end_active_trans(thd))
+      {
+        res= -1;
+        break;
+      }
+      if (!(res= Events::get_instance()->drop_event(thd, lex->spname,
+                                                    lex->drop_if_exists,
+                                                    &rows_affected)))
+        send_ok(thd, rows_affected);     
+    }
     break;
   }
 #ifndef DBUG_OFF
   case SQLCOM_SHOW_SCHEDULER_STATUS:
   {
-    res= Events::dump_internal_status(thd);
+    res= Events::get_instance()->dump_internal_status(thd);
     break;
   }
 #endif

--- 1.354/sql/sql_show.cc	2006-06-26 16:44:38 +02:00
+++ 1.355/sql/sql_show.cc	2006-06-28 15:54:07 +02:00
@@ -27,7 +27,7 @@
 #include "authors.h"
 #include "contributors.h"
 #include "events.h"
-#include "event_timed.h"
+#include "event_data_objects.h"
 #include <my_dir.h>
 
 #ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -4166,7 +4166,7 @@ extern LEX_STRING interval_type_to_name[
     1  Error
 */
 
-static int
+int
 copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
 {
   const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
@@ -4301,183 +4301,6 @@ copy_event_to_schema_table(THD *thd, TAB
 }
 
 
-/*
-  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)
-{
-  int ret=0;
-  CHARSET_INFO *scs= system_charset_info;
-  KEY *key_info;
-  uint key_len;
-  byte *key_buf= NULL;
-  LINT_INIT(key_buf);
-
-  DBUG_ENTER("schema_events_do_index_scan");
-
-  DBUG_PRINT("info", ("Using prefix scanning on PK"));
-  event_table->file->ha_index_init(0, 1);
-  event_table->field[Events::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 (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
-  {
-    ret= 1;
-    /* don't send error, it would be done by sql_alloc_error_handler() */
-  }
-  else
-  {
-    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)))
-    {
-      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);
-    }
-    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);
-}
-
-
-/*
-  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= 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);
-
-  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;
-
-  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->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);
-  }
-
-  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))
-  {
-    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->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);
-}
-
-
 int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
 {
   DBUG_ENTER("fill_open_tables");
@@ -5574,7 +5397,7 @@ ST_SCHEMA_TABLE schema_tables[]=
   {"ENGINES", engines_fields_info, create_schema_table,
    fill_schema_engines, make_old_format, 0, -1, -1, 0},
   {"EVENTS", events_fields_info, create_schema_table,
-   fill_schema_events, make_old_format, 0, -1, -1, 0},
+   Events::fill_schema_events, make_old_format, 0, -1, -1, 0},
   {"FILES", files_fields_info, create_schema_table,
    fill_schema_files, 0, 0, -1, -1, 0},
   {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,

--- 1.484/sql/sql_yacc.yy	2006-06-26 16:44:38 +02:00
+++ 1.485/sql/sql_yacc.yy	2006-06-28 15:50:49 +02:00
@@ -38,7 +38,7 @@
 #include "sp_pcontext.h"
 #include "sp_rcontext.h"
 #include "sp.h"
-#include "event_timed.h"
+#include "event_data_objects.h"
 #include <myisam.h>
 #include <myisammrg.h>
 
@@ -880,7 +880,8 @@ bool my_yyoverflow(short **a, YYSTYPE **
 	sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
         load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
         definer view_replace_or_algorithm view_replace view_algorithm_opt
-        view_algorithm view_or_trigger_or_sp view_or_trigger_or_sp_tail
+        view_algorithm view_or_trigger_or_sp_or_event
+        view_or_trigger_or_sp_or_event_tail
         view_suid view_tail view_list_opt view_list view_select
         view_check_option trigger_tail sp_tail
         install uninstall partition_entry binlog_base64_event
@@ -1257,7 +1258,33 @@ create:
 	    lex->name=$4.str;
             lex->create_info.options=$3;
 	  }
-	| CREATE EVENT_SYM opt_if_not_exists sp_name
+	| CREATE
+	  {
+            Lex->create_view_mode= VIEW_CREATE_NEW;
+            Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
+            Lex->create_view_suid= TRUE;
+	  }
+	  view_or_trigger_or_sp_or_event
+	  {}
+	| CREATE USER clear_privileges grant_list
+	  {
+	    Lex->sql_command = SQLCOM_CREATE_USER;
+          }
+	| CREATE LOGFILE_SYM GROUP logfile_group_info 
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_cmd_type= CREATE_LOGFILE_GROUP;
+          }
+        | CREATE TABLESPACE tablespace_info
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_cmd_type= CREATE_TABLESPACE;
+          }
+	;
+
+
+event_tail:
+          EVENT_SYM opt_if_not_exists sp_name
           /*
              BE CAREFUL when you add a new rule to update the block where
              YYTHD->client_capabilities is set back to original value
@@ -1268,18 +1295,19 @@ create:
             if (lex->et)
             {
               /*
-                Recursive events are not possible because recursive SPs
-                are not also possible. lex->sp_head is not stacked.
+                Recursive CREATE EVENT statement are not possible because
+                recursive SPs are not also possible. lex->sp_head is not stacked.
               */
-              // ToDo Andrey : Change the error message
               my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "EVENT");
               YYABORT;
             }
 
-            lex->create_info.options= $3;
+            lex->create_info.options= $2;
 
             if (!(lex->et= new(YYTHD->mem_root) Event_timed())) // implicitly calls Event_timed::init()
               YYABORT;
+            if (!(lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
+              YYABORT;
 
             /*
               We have to turn of CLIENT_MULTI_QUERIES while parsing a
@@ -1289,9 +1317,12 @@ create:
             $<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
             YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
 
+            
+            lex->event_parse_data->identifier= $3;
+
             if (!lex->et_compile_phase)
             {
-              lex->et->init_name(YYTHD, $4);
+              lex->et->init_name(YYTHD, $3);
               lex->et->init_definer(YYTHD);
             }
           }
@@ -1303,13 +1334,12 @@ create:
           {
             /*
               Restore flag if it was cleared above
-              $1 - CREATE
-              $2 - EVENT_SYM
-              $3 - opt_if_not_exists
-              $4 - sp_name
-              $5 - the block above
+              $1 - EVENT_SYM
+              $2 - opt_if_not_exists
+              $3 - sp_name
+              $4 - the block above
             */
-            YYTHD->client_capabilities |= $<ulong_num>5;
+            YYTHD->client_capabilities |= $<ulong_num>4;
 
             /*
               sql_command is set here because some rules in ev_sql_stmt
@@ -1317,33 +1347,12 @@ create:
             */
             Lex->sql_command= SQLCOM_CREATE_EVENT;
           }
-	| CREATE
-	  {
-            Lex->create_view_mode= VIEW_CREATE_NEW;
-            Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
-            Lex->create_view_suid= TRUE;
-	  }
-	  view_or_trigger_or_sp
-	  {}
-	| CREATE USER clear_privileges grant_list
-	  {
-	    Lex->sql_command = SQLCOM_CREATE_USER;
-          }
-	| CREATE LOGFILE_SYM GROUP logfile_group_info 
-          {
-            LEX *lex= Lex;
-            lex->alter_tablespace_info->ts_cmd_type= CREATE_LOGFILE_GROUP;
-          }
-        | CREATE TABLESPACE tablespace_info
-          {
-            LEX *lex= Lex;
-            lex->alter_tablespace_info->ts_cmd_type= CREATE_TABLESPACE;
-          }
-	;
 
 
 ev_schedule_time: EVERY_SYM expr interval
 	  {
+            Lex->event_parse_data->item_expression= $2;
+            Lex->event_parse_data->interval= $3;
             LEX *lex=Lex;
             if (!lex->et_compile_phase)
             {
@@ -1365,6 +1374,7 @@ ev_schedule_time: EVERY_SYM expr interva
           ev_ends
         | AT_SYM expr
           {
+            Lex->event_parse_data->item_execute_at= $2;
             LEX *lex=Lex;
             if (!lex->et_compile_phase)
             {
@@ -1395,6 +1405,7 @@ ev_schedule_time: EVERY_SYM expr interva
 opt_ev_status: /* empty */ { $$= 0; }
         | ENABLE_SYM
           {
+            Lex->event_parse_data->status= Event_parse_data::ENABLED;
             LEX *lex=Lex;
             if (!lex->et_compile_phase)
               lex->et->status= Event_timed::ENABLED;
@@ -1402,6 +1413,7 @@ opt_ev_status: /* empty */ { $$= 0; }
           }
         | DISABLE_SYM
           {
+            Lex->event_parse_data->status= Event_parse_data::DISABLED;
             LEX *lex=Lex;
 
             if (!lex->et_compile_phase)
@@ -1412,10 +1424,12 @@ opt_ev_status: /* empty */ { $$= 0; }
 
 ev_starts: /* empty */
           {
+            Lex->event_parse_data->item_starts= new Item_func_now_local();
             Lex->et->init_starts(YYTHD, new Item_func_now_local());
           }
         | STARTS_SYM expr
           {
+            Lex->event_parse_data->item_starts= $2;
             LEX *lex= Lex;
             if (!lex->et_compile_phase)
             {
@@ -1443,6 +1457,7 @@ ev_starts: /* empty */
 ev_ends: /* empty */
         | ENDS_SYM expr
           {
+            Lex->event_parse_data->item_ends= $2;
             LEX *lex= Lex;
             if (!lex->et_compile_phase)
             {
@@ -1467,6 +1482,8 @@ opt_ev_on_completion: /* empty */ { $$= 
 ev_on_completion:
           ON COMPLETION_SYM PRESERVE_SYM
           {
+            Lex->event_parse_data->on_completion=
+                                  Event_parse_data::ON_COMPLETION_PRESERVE;
             LEX *lex=Lex;
             if (!lex->et_compile_phase)
               lex->et->on_completion= Event_timed::ON_COMPLETION_PRESERVE;
@@ -1474,6 +1491,8 @@ ev_on_completion:
           }
         | ON COMPLETION_SYM NOT_SYM PRESERVE_SYM
           {
+            Lex->event_parse_data->on_completion=
+                                  Event_parse_data::ON_COMPLETION_DROP;
             LEX *lex=Lex;
             if (!lex->et_compile_phase)
               lex->et->on_completion= Event_timed::ON_COMPLETION_DROP;
@@ -1484,6 +1503,7 @@ ev_on_completion:
 opt_ev_comment: /* empty */ { $$= 0; }
         | COMMENT_SYM TEXT_STRING_sys
           {
+            Lex->comment= Lex->event_parse_data->comment= $2;
             LEX *lex= Lex;
             if (!lex->et_compile_phase)
             {
@@ -1499,25 +1519,43 @@ ev_sql_stmt:
             LEX *lex= Lex;
             sp_head *sp;
 
-            $<sphead>$= lex->sphead;
-
-            if (!lex->sphead)
+            /*
+              This stops the following :
+              - CREATE EVENT ... DO CREATE EVENT ...;
+              - ALTER  EVENT ... DO CREATE EVENT ...;
+              - CREATE EVENT ... DO ALTER EVENT DO ....;
+              - CREATE PROCEDURE ... BEGIN CREATE EVENT ... END|
+              This allows:
+              - CREATE EVENT ... DO DROP EVENT yyy;
+              - CREATE EVENT ... DO ALTER EVENT yyy;
+                (the nested ALTER EVENT can have anything but DO clause)
+              - ALTER  EVENT ... DO ALTER EVENT yyy;
+                (the nested ALTER EVENT can have anything but DO clause)
+              - ALTER  EVENT ... DO DROP EVENT yyy;
+              - CREATE PROCEDURE ... BEGIN ALTER EVENT ... END|
+                (the nested ALTER EVENT can have anything but DO clause)
+              - CREATE PROCEDURE ... BEGIN DROP EVENT ... END|
+            */
+            if (lex->sphead)
             {
-              if (!(sp= new sp_head()))
-                YYABORT;
-
-              sp->reset_thd_mem_root(YYTHD);
-              sp->init(lex);
+              my_error(ER_EVENT_RECURSIVITY_FORBIDDEN, MYF(0));
+              YYABORT;
+            }
+              
+            if (!(lex->sphead= new sp_head()))
+              YYABORT;
 
-              sp->m_type= TYPE_ENUM_PROCEDURE;
+            lex->sphead->reset_thd_mem_root(YYTHD);
+            lex->sphead->init(lex);
 
-              lex->sphead= sp;
+            lex->sphead->m_type= TYPE_ENUM_PROCEDURE;
 
-              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;
+            
+            Lex->event_parse_data->body_begin= lex->ptr;
 
             if (!lex->et_compile_phase)
               lex->et->body_begin= lex->ptr;
@@ -1526,18 +1564,16 @@ ev_sql_stmt:
           {
             LEX *lex=Lex;
 
-            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);
+            // return back to the original memory root ASAP
+            lex->sphead->init_strings(YYTHD, lex, NULL);
+            lex->sphead->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;
-            }
+            lex->et->sphead= lex->sphead;
+            lex->sphead= NULL;
+
+            Lex->event_parse_data->init_body(YYTHD);
             if (!lex->et_compile_phase)
             {
               lex->et->init_body(YYTHD);
@@ -4720,16 +4756,11 @@ alter:
             LEX *lex=Lex;
             Event_timed *et;
 
-            if (lex->et)
-            {
-              /*
-                Recursive events are not possible because recursive SPs
-                are not also possible. lex->sp_head is not stacked.
-              */
-              my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "EVENT");
+            lex->spname= NULL;
+
+            if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
               YYABORT;
-            }
-            lex->spname= 0;//defensive programming
+            Lex->event_parse_data->identifier= $3;
 
             if (!(et= new (YYTHD->mem_root) Event_timed()))// implicitly calls Event_timed::init()
               YYABORT;
@@ -4742,9 +4773,9 @@ alter:
             }
 
             /*
-                We have to turn of CLIENT_MULTI_QUERIES while parsing a
-                stored procedure, otherwise yylex will chop it into pieces
-                at each ';'.
+              We have to turn of CLIENT_MULTI_QUERIES while parsing a
+              stored procedure, otherwise yylex will chop it into pieces
+              at each ';'.
             */
             $<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
             YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
@@ -7664,29 +7695,9 @@ drop:
 	  }
         | DROP EVENT_SYM if_exists sp_name
           {
-            LEX *lex=Lex;
-
-            if (lex->et)
-            {
-              /*
-                Recursive events are not possible because recursive SPs
-                are not also possible. lex->sp_head is not stacked.
-              */
-              my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "EVENT");
-              YYABORT;
-            }
-
-            if (!(lex->et= new (YYTHD->mem_root) Event_timed()))
-              YYABORT;
-	  
-            if (!lex->et_compile_phase)
-            {
-              lex->et->init_name(YYTHD, $4);
-              lex->et->init_definer(YYTHD);
-            }
-
-            lex->sql_command = SQLCOM_DROP_EVENT;
-            lex->drop_if_exists= $3;
+            Lex->drop_if_exists= $3;
+            Lex->spname= $4;
+            Lex->sql_command = SQLCOM_DROP_EVENT;
           }
         | DROP TRIGGER_SYM sp_name
           {
@@ -8416,12 +8427,8 @@ show_param:
           }
         | CREATE EVENT_SYM sp_name
           {
-            Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT;
             Lex->spname= $3;
-            Lex->et= new (YYTHD->mem_root) Event_timed();
-            if (!Lex->et)
-              YYABORT;
-            Lex->et->init_definer(YYTHD);
+            Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT;
           }
       ;
 
@@ -10751,19 +10758,21 @@ subselect_end:
 
 **************************************************************************/
 
-view_or_trigger_or_sp:
-	definer view_or_trigger_or_sp_tail
+view_or_trigger_or_sp_or_event:
+	definer view_or_trigger_or_sp_or_event_tail
 	{}
 	| view_replace_or_algorithm definer view_tail
 	{}
 	;
 
-view_or_trigger_or_sp_tail:
+view_or_trigger_or_sp_or_event_tail:
 	view_tail
 	{}
 	| trigger_tail
 	{}
 	| sp_tail
+	{}
+	| event_tail
 	{}
 	;
 

--- 1.45/sql/events.cc	2006-06-26 16:44:37 +02:00
+++ 1.46/sql/events.cc	2006-06-28 15:50:47 +02:00
@@ -15,11 +15,10 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 #include "mysql_priv.h"
-#include "events_priv.h"
 #include "events.h"
-#include "event_timed.h"
+#include "event_data_objects.h"
 #include "event_scheduler.h"
-#include "sp.h"
+#include "event_db_repository.h"
 #include "sp_head.h"
 
 /*
@@ -48,10 +47,6 @@ Warning:
 */
 
 
-MEM_ROOT evex_mem_root;
-time_t mysql_event_last_create_time= 0L;
-
-
 const char *event_scheduler_state_names[]=
     { "OFF", "0", "ON", "1", "SUSPEND", "2", NullS };
 
@@ -63,104 +58,10 @@ TYPELIB Events::opt_typelib=
   NULL
 };
 
+Events Events::singleton;
 
 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)")},
-    {(char *) STRING_WITH_LEN("utf8")}
-  }, 
-  {
-    {(char *) STRING_WITH_LEN("name")},
-    {(char *) STRING_WITH_LEN("char(64)")},
-    {(char *) STRING_WITH_LEN("utf8")}
-  },
-  {
-    {(char *) STRING_WITH_LEN("body")},
-    {(char *) STRING_WITH_LEN("longblob")},
-    {NULL, 0}
-  }, 
-  {
-    {(char *) STRING_WITH_LEN("definer")},
-    {(char *) STRING_WITH_LEN("char(77)")},
-    {(char *) STRING_WITH_LEN("utf8")}
-  },
-  {
-    {(char *) STRING_WITH_LEN("execute_at")},
-    {(char *) STRING_WITH_LEN("datetime")},
-    {NULL, 0}
-  }, 
-  {
-    {(char *) STRING_WITH_LEN("interval_value")},
-    {(char *) STRING_WITH_LEN("int(11)")},
-    {NULL, 0}
-  },
-  {
-    {(char *) STRING_WITH_LEN("interval_field")},
-    {(char *) STRING_WITH_LEN("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')")},
-    {NULL, 0}
-  }, 
-  {
-    {(char *) STRING_WITH_LEN("created")},
-    {(char *) STRING_WITH_LEN("timestamp")},
-    {NULL, 0}
-  },
-  {
-    {(char *) STRING_WITH_LEN("modified")},
-    {(char *) STRING_WITH_LEN("timestamp")},
-    {NULL, 0}
-  }, 
-  {
-    {(char *) STRING_WITH_LEN("last_executed")},
-    {(char *) STRING_WITH_LEN("datetime")},
-    {NULL, 0}
-  },
-  {
-    {(char *) STRING_WITH_LEN("starts")},
-    {(char *) STRING_WITH_LEN("datetime")},
-    {NULL, 0}
-  }, 
-  {
-    {(char *) STRING_WITH_LEN("ends")},
-    {(char *) STRING_WITH_LEN("datetime")},
-    {NULL, 0}
-  },
-  {
-    {(char *) STRING_WITH_LEN("status")},
-    {(char *) STRING_WITH_LEN("enum('ENABLED','DISABLED')")},
-    {NULL, 0}
-  }, 
-  {
-    {(char *) STRING_WITH_LEN("on_completion")},
-    {(char *) STRING_WITH_LEN("enum('DROP','PRESERVE')")},
-    {NULL, 0}
-  },
-  {
-    {(char *) STRING_WITH_LEN("sql_mode")},
-    {(char *) STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES',"
-    "'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION',"
-    "'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB',"
-    "'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40',"
-    "'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES',"
-    "'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES',"
-    "'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER',"
-    "'HIGH_NOT_PRECEDENCE')")},
-    {NULL, 0}
-  },
-  {
-    {(char *) STRING_WITH_LEN("comment")},
-    {(char *) STRING_WITH_LEN("char(64)")},
-    {(char *) STRING_WITH_LEN("utf8")}
-  }
-};
-
 
 /*
   Compares 2 LEX strings regarding case.
@@ -187,6 +88,23 @@ int sortcmp_lex_string(LEX_STRING s, LEX
                                   (uchar *) t.str,t.length, 0);
 }
 
+/*
+  Accessor for the singleton instance.
+
+  SYNOPSIS
+    Events::get_instance()
+
+  RETURN VALUE
+    address  
+*/
+
+Events *
+Events::get_instance()
+{
+  DBUG_ENTER("Events::get_instance");
+  DBUG_RETURN(&singleton);
+}
+
 
 /*
   Reconstructs interval expression from interval type and expression
@@ -201,15 +119,14 @@ int sortcmp_lex_string(LEX_STRING s, LEX
       interval - the interval type (for instance YEAR_MONTH)
       expression - the value in the lowest entity
 
-  RETURNS
+  RETURN VALUE
    0 - OK
    1 - Error
 */
 
 int
-Events::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;
@@ -341,545 +258,7 @@ int
 Events::open_event_table(THD *thd, enum thr_lock_type lock_type,
                                    TABLE **table)
 {
-  TABLE_LIST tables;
-  DBUG_ENTER("open_events_table");
-
-  bzero((char*) &tables, sizeof(tables));
-  tables.db= (char*) "mysql";
-  tables.table_name= tables.alias= (char*) "event";
-  tables.lock_type= lock_type;
-
-  if (simple_open_n_lock_tables(thd, &tables))
-    DBUG_RETURN(1);
-  
-  if (table_check_intact(tables.table, Events::FIELD_COUNT,
-                         event_table_fields,
-                         &mysql_event_last_create_time,
-                         ER_CANNOT_LOAD_FROM_TABLE))
-  {
-    close_thread_tables(thd);
-    DBUG_RETURN(2);
-  }
-  *table= tables.table;
-  tables.table->use_all_columns();
-  DBUG_RETURN(0);
-}
-
-
-/*
-  Find row in open mysql.event table representing event
-
-  SYNOPSIS
-    evex_db_find_event_aux()
-      thd    Thread context
-      et     event_timed object containing dbname & name
-      table  TABLE object for open mysql.event table.
-
-  RETURN VALUE
-    0                  - Routine found
-    EVEX_KEY_NOT_FOUND - No routine with given name
-*/
-
-inline int
-evex_db_find_event_aux(THD *thd, Event_timed *et, TABLE *table)
-{
-  return evex_db_find_event_by_name(thd, et->dbname, et->name, table);
-}
-
-
-/*
-  Find row in open mysql.event table representing event
-
-  SYNOPSIS
-    evex_db_find_event_by_name()
-      thd    Thread context
-      dbname Name of event's database
-      rname  Name of the event inside the db  
-      table  TABLE object for open mysql.event table.
-
-  RETURN VALUE
-    0                  - Routine found
-    EVEX_KEY_NOT_FOUND - No routine with given name
-*/
-
-int
-evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
-                          const LEX_STRING ev_name,
-                          TABLE *table)
-{
-  byte key[MAX_KEY_LENGTH];
-  DBUG_ENTER("evex_db_find_event_by_name");
-  DBUG_PRINT("enter", ("name: %.*s", ev_name.length, ev_name.str));
-
-  /*
-    Create key to find row. We have to use field->store() to be able to
-    handle VARCHAR and CHAR fields.
-    Assumption here is that the two first fields in the table are
-    'db' and 'name' and the first key is the primary key over the
-    same fields.
-  */
-  if (dbname.length > table->field[Events::FIELD_DB]->field_length ||
-      ev_name.length > table->field[Events::FIELD_NAME]->field_length)
-      
-    DBUG_RETURN(EVEX_KEY_NOT_FOUND);
-
-  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,
-                                          &my_charset_bin);
-
-  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 found"));
-    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.
-
-  SYNOPSIS
-    evex_fill_row()
-      thd    THD
-      table  the row to fill out
-      et     Event's data
-
-  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 Events::enum_table_field field_num;
-
-  DBUG_ENTER("evex_fill_row");
-
-  DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
-  DBUG_PRINT("info", ("name  =[%s]", et->name.str));
-  DBUG_PRINT("info", ("body  =[%s]", et->body.str));
-
-  if (table->field[field_num= Events::FIELD_DEFINER]->
-                  store(et->definer.str, et->definer.length, scs))
-    goto err_truncate;
-
-  if (table->field[field_num= Events::FIELD_DB]->
-                  store(et->dbname.str, et->dbname.length, scs))
-    goto err_truncate;
-
-  if (table->field[field_num= Events::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[Events::FIELD_ON_COMPLETION]->
-                                       store((longlong)et->on_completion, 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
-    always during CREATE EVENT.
-  */ 
-  if (et->body.str)
-  {
-    table->field[Events::FIELD_SQL_MODE]->
-                               store((longlong)thd->variables.sql_mode, true);
-
-    if (table->field[field_num= Events::FIELD_BODY]->
-                     store(et->body.str, et->body.length, scs))
-      goto err_truncate;
-  }
-
-  if (et->expression)
-  {
-    table->field[Events::FIELD_INTERVAL_EXPR]->set_notnull();
-    table->field[Events::FIELD_INTERVAL_EXPR]->
-                                          store((longlong)et->expression, true);
-
-    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[Events::FIELD_TRANSIENT_INTERVAL]->
-                                         store((longlong)et->interval+1, true);
-
-    table->field[Events::FIELD_EXECUTE_AT]->set_null();
-
-    if (!et->starts_null)
-    {
-      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[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[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[Events::FIELD_EXECUTE_AT]->set_notnull();
-    table->field[Events::FIELD_EXECUTE_AT]->
-                        store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
-  }
-  else
-  {
-    DBUG_ASSERT(is_update);
-    /*
-      it is normal to be here when the action is update
-      this is an error if the action is create. something is borked
-    */
-  }
-    
-  ((Field_timestamp *)table->field[Events::FIELD_MODIFIED])->set_time();
-
-  if (et->comment.str)
-  {
-    if (table->field[field_num= Events::FIELD_COMMENT]->
-                 store(et->comment.str, et->comment.length, scs))
-      goto err_truncate;
-  }
-
-  DBUG_RETURN(0);
-err_truncate:
-  my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), table->field[field_num]->field_name);
-  DBUG_RETURN(EVEX_GENERAL_ERROR);
-}
-
-
-/*
-  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
-
-  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".
-*/
-
-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;
-  DBUG_ENTER("db_create_event");
-  DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
-
-  *rows_affected= 0;
-  DBUG_PRINT("info", ("open mysql.event for update"));
-  if (Events::open_event_table(thd, TL_WRITE, &table))
-  {
-    my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
-    goto err;
-  }
-
-  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)
-    {
-      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
-                          ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
-                          et->name.str);
-      goto ok;
-    }
-    my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), et->name.str);
-    goto err;
-  }
-
-  DBUG_PRINT("info", ("non-existant, go forward"));
-  if ((ret= sp_use_new_db(thd, et->dbname.str,olddb, sizeof(olddb),0,
-                          &dbchanged)))
-  {
-    my_error(ER_BAD_DB_ERROR, MYF(0));
-    goto err;
-  }
-
-  restore_record(table, s->default_values);     // Get default values for fields
-
-  if (system_charset_info->cset->numchars(system_charset_info, et->dbname.str,
-                                    et->dbname.str + et->dbname.length)
-                                    > EVEX_DB_FIELD_LEN)
-  {
-    my_error(ER_TOO_LONG_IDENT, MYF(0), et->dbname.str);
-    goto err;
-  }
-  if (system_charset_info->cset->numchars(system_charset_info, et->name.str,
-                                    et->name.str + et->name.length)
-                                    > EVEX_DB_FIELD_LEN)
-  {
-    my_error(ER_TOO_LONG_IDENT, MYF(0), et->name.str);
-    goto err;
-  }
-
-  if (et->body.length > table->field[Events::FIELD_BODY]->field_length)
-  {
-    my_error(ER_TOO_LONG_BODY, MYF(0), et->name.str);
-    goto err;
-  }
-
-  if (!(et->expression) && !(et->execute_at.year))
-  {
-    DBUG_PRINT("error", ("neither expression nor execute_at are set!"));
-    my_error(ER_EVENT_NEITHER_M_EXPR_NOR_M_AT, MYF(0));
-    goto err;
-  }
-
-  ((Field_timestamp *)table->field[Events::FIELD_CREATED])->set_time();
-
-  /*
-    evex_fill_row() calls my_error() in case of error so no need to
-    handle it here
-  */
-  if ((ret= evex_fill_row(thd, table, et, false)))
-    goto err; 
-
-  if (table->file->ha_write_row(table->record[0]))
-  {
-    my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
-    goto err;
-  }
-
-#ifdef USE_THIS_CODE_AS_TEMPLATE_WHEN_EVENT_REPLICATION_IS_AGREED
-  if (mysql_bin_log.is_open())
-  {
-    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);
-  }
-#endif
-
-  *rows_affected= 1;
-ok:
-  if (dbchanged)
-    (void) mysql_change_db(thd, olddb, 1);
-  if (table)
-    close_thread_tables(thd);
-  DBUG_RETURN(EVEX_OK);
-
-err:
-  if (dbchanged)
-    (void) mysql_change_db(thd, olddb, 1);
-  if (table)
-    close_thread_tables(thd);
-  DBUG_RETURN(EVEX_GENERAL_ERROR);
-}
-
-
-/*
-  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)
-
-  NOTES
-    sp_name is passed since this is the name of the event to
-    alter in case of RENAME TO.
-*/
-
-static int
-db_update_event(THD *thd, Event_timed *et, sp_name *new_name)
-{
-  CHARSET_INFO *scs= system_charset_info;
-  TABLE *table;
-  int ret= EVEX_OPEN_TABLE_FAILED;
-  DBUG_ENTER("db_update_event");
-  DBUG_PRINT("enter", ("dbname: %.*s", et->dbname.length, et->dbname.str));
-  DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
-  DBUG_PRINT("enter", ("user: %.*s", et->definer.length, et->definer.str));
-  if (new_name)
-    DBUG_PRINT("enter", ("rename to: %.*s", new_name->m_name.length,
-                                            new_name->m_name.str));
-
-  if (Events::open_event_table(thd, TL_WRITE, &table))
-  {
-    my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
-    goto err;
-  }
-  
-  /* first look whether we overwrite */
-  if (new_name)
-  {
-    if (!sortcmp_lex_string(et->name, new_name->m_name, scs) &&
-        !sortcmp_lex_string(et->dbname, new_name->m_db, scs))
-    {
-      my_error(ER_EVENT_SAME_NAME, MYF(0), et->name.str);
-      goto err;    
-    }
-  
-    if (!evex_db_find_event_by_name(thd,new_name->m_db,new_name->m_name,table))
-    {
-      my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str);
-      goto err;
-    }  
-  }
-  /*
-    ...and then if there is such an event. Don't exchange the blocks
-    because you will get error 120 from table handler because new_name will
-    overwrite the key and SE will tell us that it cannot find the already found
-    row (copied into record[1] later
-  */
-  if (EVEX_KEY_NOT_FOUND == evex_db_find_event_aux(thd, et, table))
-  {
-    my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str);
-    goto err;
-  }
-
-  store_record(table,record[1]);
-
-  /* Don't update create on row update. */
-  table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
-
-  /*
-    evex_fill_row() calls my_error() in case of error so no need to
-    handle it here
-  */
-  if ((ret= evex_fill_row(thd, table, et, true)))
-    goto err;
-
-  if (new_name)
-  {    
-    table->field[Events::FIELD_DB]->
-      store(new_name->m_db.str, new_name->m_db.length, scs);
-    table->field[Events::FIELD_NAME]->
-      store(new_name->m_name.str, new_name->m_name.length, scs);
-  }
-
-  if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
-  {
-    my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
-    goto err;
-  }
-
-  /* close mysql.event or we crash later when loading the event from disk */
-  close_thread_tables(thd);
-  DBUG_RETURN(0);
-
-err:
-  if (table)
-    close_thread_tables(thd);
-  DBUG_RETURN(EVEX_GENERAL_ERROR);
-}
-
-
-/*
-  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
-      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
-*/
-
-int
-db_find_event(THD *thd, sp_name *name, Event_timed **ett, TABLE *tbl,
-              MEM_ROOT *root)
-{
-  TABLE *table;
-  int ret;
-  Event_timed *et= NULL;
-  DBUG_ENTER("db_find_event");
-  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
-
-  if (!root)
-    root= &evex_mem_root;
-
-  if (tbl)
-    table= tbl;
-  else if (Events::open_event_table(thd, TL_READ, &table))
-  {
-    my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
-    ret= EVEX_GENERAL_ERROR;
-    goto done;
-  }
-
-  if ((ret= evex_db_find_event_by_name(thd, name->m_db, name->m_name, table)))
-  {
-    my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name->m_name.str);
-    goto done;    
-  }
-  et= new Event_timed;
-  
-  /*
-    1)The table should not be closed beforehand.  ::load_from_row() only loads
-      and does not compile
-
-    2)::load_from_row() is silent on error therefore we emit error msg here
-  */
-  if ((ret= et->load_from_row(root, table)))
-  {
-    my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0));
-    goto done;
-  }
-
-done:
-  if (ret)
-  {
-    delete et;
-    et= 0;
-  }
-  /* don't close the table if we haven't opened it ourselves */
-  if (!tbl && table)
-    close_thread_tables(thd);
-  *ett= et;
-  DBUG_RETURN(ret);
+  return db_repository->open_event_table(thd, lock_type, table);
 }
 
 
@@ -904,8 +283,8 @@ done:
 */
 
 int
-Events::create_event(THD *thd, Event_timed *et, uint create_options,
-                     uint *rows_affected)
+Events::create_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
+                     uint create_options, uint *rows_affected)
 {
   int ret;
 
@@ -913,9 +292,10 @@ Events::create_event(THD *thd, Event_tim
   DBUG_PRINT("enter", ("name: %*s options:%d", et->name.length,
                 et->name.str, create_options));
 
-  if (!(ret = db_create_event(thd, et,
-                             create_options & HA_LEX_CREATE_IF_NOT_EXISTS,
-                             rows_affected)))
+  if (!(ret= db_repository->
+                 create_event(thd, et,
+                              create_options & HA_LEX_CREATE_IF_NOT_EXISTS,
+                              rows_affected)))
   {
     Event_scheduler *scheduler= Event_scheduler::get_instance();
     if (scheduler->initialized() &&
@@ -948,8 +328,8 @@ Events::create_event(THD *thd, Event_tim
 */
 
 int
-Events::update_event(THD *thd, Event_timed *et, sp_name *new_name,
-                               uint *rows_affected)
+Events::update_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
+                     sp_name *new_name, uint *rows_affected)
 {
   int ret;
 
@@ -960,7 +340,7 @@ Events::update_event(THD *thd, Event_tim
     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)))
+  if (!(ret= db_repository->update_event(thd, et, new_name)))
   {
     Event_scheduler *scheduler= Event_scheduler::get_instance();
     if (scheduler->initialized() &&
@@ -977,74 +357,9 @@ Events::update_event(THD *thd, Event_tim
   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
-
-  RETURN VALUE
-    0   OK
-    !0  Error (my_error() called)
-*/
-
-int db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
-                  uint *rows_affected)
-{
-  TABLE *table;
-  Open_tables_state backup;
-  int ret;
-
-  DBUG_ENTER("db_drop_event");
-  ret= EVEX_OPEN_TABLE_FAILED;
-
-  thd->reset_n_backup_open_tables_state(&backup);
-  if (Events::open_event_table(thd, TL_WRITE, &table))
-  {
-    my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
-    goto done;
-  }
-
-  if (!(ret= evex_db_find_event_aux(thd, et, table)))
-  {
-    if ((ret= table->file->ha_delete_row(table->record[0])))
-    { 	
-      my_error(ER_EVENT_CANNOT_DELETE, MYF(0));
-      goto done;
-    }
-  }
-  else if (ret == EVEX_KEY_NOT_FOUND)
-  { 
-    if (drop_if_exists)
-    {
-      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
-                          ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
-                          "Event", et->name.str);
-      ret= 0;
-    } else
-      my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str);
-    goto done;
-  }
-
-
-done:
-  /*
-    evex_drop_event() is used by Event_timed::drop therefore
-    we have to close our thread tables.
-  */
-  close_thread_tables(thd);
-  thd->restore_backup_open_tables_state(&backup);
-  DBUG_RETURN(ret);
-}
-
-
-/*
-  Drops an event
-
-  SYNOPSIS
     Events::drop_event()
       thd             THD
-      et              event's name
+      name            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
 
@@ -1054,19 +369,20 @@ done:
 */
 
 int
-Events::drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
-                             uint *rows_affected)
+Events::drop_event(THD *thd, sp_name *name, bool drop_if_exists,
+                   uint *rows_affected)
 {
   int ret;
 
   DBUG_ENTER("Events::drop_event");
-  if (!(ret= db_drop_event(thd, et, drop_if_exists, rows_affected)))
+
+  if (!(ret= db_repository->drop_event(thd, name->m_db, name->m_name,
+                                      drop_if_exists, rows_affected)))
   {
     Event_scheduler *scheduler= Event_scheduler::get_instance();
-    if (scheduler->initialized() && (ret= scheduler->drop_event(thd, et)))
+    if (scheduler->initialized() && (ret= scheduler->drop_event(thd, name)))
       my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
   }
-
   DBUG_RETURN(ret);
 }
 
@@ -1091,11 +407,11 @@ Events::show_create_event(THD *thd, sp_n
   Event_timed *et= NULL;
   Open_tables_state backup;
 
-  DBUG_ENTER("evex_update_event");
+  DBUG_ENTER("Events::show_create_event");
   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_repository->find_event(thd, spn, &et, NULL, thd->mem_root);
   thd->restore_backup_open_tables_state(&backup);
 
   if (!ret)
@@ -1167,76 +483,14 @@ Events::drop_schema_events(THD *thd, cha
   DBUG_PRINT("enter", ("dropping events from %s", db));
 
   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);
+  ret= scheduler->drop_schema_events(thd, db_lex);
+  ret= db_repository->drop_schema_events(thd, db_lex);
 
   DBUG_RETURN(ret);
 }
 
 
 /*
-  Drops all events in the selected database, from mysql.event.
-
-  SYNOPSIS
-    evex_drop_db_events_from_table()
-      thd  Thread
-      db   Schema name
-
-  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)))
-  {
-    if (my_errno != ENOENT)
-      sql_print_error("Table mysql.event is damaged. Got error %d on open",
-                      my_errno);
-    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);
-  while (!(read_record_info.read_record(&read_record_info)) && !ret)
-  {
-    char *et_db= get_field(thd->mem_root,
-                           table->field[Events::FIELD_DB]);
-
-    LEX_STRING et_db_lex= {et_db, strlen(et_db)};
-    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))
-    {
-      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]));
-    }
-  }
-  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
@@ -1254,14 +508,16 @@ int
 Events::init()
 {
   int ret= 0;
+  Event_db_repository *db_repo;
   DBUG_ENTER("Events::init");
+  db_repository->init_repository();
 
   /* 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() || 
+    DBUG_RETURN(scheduler->init(db_repository) || 
                 (opt_event_scheduler == 1? scheduler->start():
                                            scheduler->start_suspended()));
   }
@@ -1273,16 +529,17 @@ Events::init()
   Cleans up scheduler's resources. Called at server shutdown.
 
   SYNOPSIS
-    Events::shutdown()
+    Events::deinit()
 
   NOTES
     This function is not synchronized.
 */
 
 void
-Events::shutdown()
+Events::deinit()
 {
-  DBUG_ENTER("Events::shutdown");
+  DBUG_ENTER("Events::deinit");
+
   Event_scheduler *scheduler= Event_scheduler::get_instance();
   if (scheduler->initialized())
   {
@@ -1290,26 +547,9 @@ Events::shutdown()
     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
-*/
+  db_repository->deinit_repository();
 
-int
-Events::dump_internal_status(THD *thd)
-{
-  return Event_scheduler::dump_internal_status(thd);
+  DBUG_VOID_RETURN;
 }
 
 
@@ -1324,6 +564,7 @@ Events::dump_internal_status(THD *thd)
 void
 Events::init_mutexes()
 {
+  db_repository= new Event_db_repository;
   Event_scheduler::init_mutexes();
 }
 
@@ -1339,4 +580,61 @@ void
 Events::destroy_mutexes()
 {
   Event_scheduler::destroy_mutexes();
+  delete db_repository;
+  db_repository= NULL;
+}
+
+
+/*
+  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);
+}
+
+
+/*
+  Proxy for Event_db_repository::fill_schema_events.
+  Callback for I_S from sql_show.cc
+
+  SYNOPSIS
+    Events::fill_schema_events()
+      thd     Thread
+      tables  The schema table
+      cond    Unused
+
+  RETURN VALUE
+    0  OK
+    !0 Error
+*/
+
+int
+Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
+{
+  char *db= NULL;
+  DBUG_ENTER("Events::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);
+    db= thd->lex->select_lex.db;
+  }
+  DBUG_RETURN(get_instance()->db_repository->fill_schema_events(thd, tables, db));
 }

--- 1.178/sql/set_var.cc	2006-06-23 01:49:15 +02:00
+++ 1.179/sql/set_var.cc	2006-06-28 15:50:48 +02:00
@@ -3892,7 +3892,7 @@ byte *sys_var_thd_dbug::value_ptr(THD *t
 bool
 sys_var_event_scheduler::update(THD *thd, set_var *var)
 {
-  enum Event_scheduler::enum_error_code res;
+  int res;
   Event_scheduler *scheduler= Event_scheduler::get_instance();
   /* here start the thread if not running. */
   DBUG_ENTER("sys_var_event_scheduler::update");

--- 1.23/sql/CMakeLists.txt	2006-06-26 16:44:37 +02:00
+++ 1.24/sql/CMakeLists.txt	2006-06-28 15:50:47 +02:00
@@ -51,7 +51,8 @@ ADD_EXECUTABLE(mysqld ../sql-common/clie
                sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
                sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc 
                time.cc tztime.cc uniques.cc unireg.cc item_xmlfunc.cc 
-               rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_timed.cc 
+               rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_data_objects.cc
+               event_queue.cc event_db_repository.cc 
                sql_tablespace.cc events.cc ../sql-common/my_user.c 
                partition_info.cc rpl_injector.cc
                ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
Thread
bk commit into 5.1 tree (andrey:1.2222)ahristov28 Jun