List:Commits« Previous MessageNext Message »
From:ahristov Date:March 26 2006 12:22pm
Subject:bk commit into 5.1 tree (andrey:1.2213) BUG#16394
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.2213 06/03/26 14:22:27 andrey@lmy004. +14 -0
  fix for bug #16394: Events: Crash if schedule contains SELECT
  (SUBSelects are forbidden, though the infrastructure is there,
   by allowing subselects with lex->command_forbid_subselect=false
   one can experiment with subqueries. For now disabled, can be
   enabled in the future when we have less bugs on the plate)
  -later checking, not in the parser, of the parameters is implemented
   thus CREATE EVENT xyz ON SCHEDULE EVERY NULL SECOND, gives a syntax error now,
   used to give an error about invalid value for EVERY.
  -this lifts off the limitation that ENDS > STARTS, now ENDS >= STARTS
  (after first code review)

  sql/sql_yacc.yy
    1.472 06/03/26 14:22:13 andrey@lmy004. +58 -91
    - use late fix_fields of AT/EVERY/STARTS/ENDS
    - some commands cannot handle, or don't want to handle SUBqueries, so
      give them a way to express that -> lex->command_forbid_subselect

  sql/sql_show.cc
    1.316 06/03/26 14:22:13 andrey@lmy004. +15 -1
    - trace info to SELECT FROM I_S.PROCESSLIST, in the trace log we didn't see
      what goes to the user.

  sql/sql_prepare.cc
    1.165 06/03/26 14:22:13 andrey@lmy004. +26 -9
    - more data to trace log. It's always nice for tracking to know
      the number of the PS (stmt_id).

  sql/sql_parse.cc
    1.527 06/03/26 14:22:13 andrey@lmy004. +1 -1
    - print time (with microseconds) in the trace log.

  sql/sql_lex.h
    1.218 06/03/26 14:22:13 andrey@lmy004. +8 -0
    - new variable to st_lex

  sql/sql_lex.cc
    1.172 06/03/26 14:22:13 andrey@lmy004. +1 -0
    - add a member variable to help in cases where SUBSELECT is inappropriate

  sql/sql_base.cc
    1.310 06/03/26 14:22:12 andrey@lmy004. +1 -0
    - trace log message

  sql/sp_head.cc
    1.211 06/03/26 14:22:12 andrey@lmy004. +3 -2
    - move the code before the comment, where it's more appropriate

  sql/event_timed.cc
    1.46 06/03/26 14:22:12 andrey@lmy004. +113 -28
    - late parsing of the AT/EVERY/STARTS/ENDS to support SUBqueries

  sql/event_executor.cc
    1.42 06/03/26 14:22:12 andrey@lmy004. +33 -8
    - 1s is too much time for sleeping, kick in.
    - add timing to mysqld.trace, much easier to track timing problems with it. (threads switching)

  sql/event.h
    1.27 06/03/26 14:22:12 andrey@lmy004. +14 -1
    - add member variables to class Event_timed which are used for the late
      checking of Item* (not in the parser).

  sql/event.cc
    1.38 06/03/26 14:22:12 andrey@lmy004. +171 -46
    - initialization of AT, EVERY, STARTS and ENDS moved from the parser to after parsing
    - tables are opened in one shot, a subquery may open mysql.event again but for read (
      SELECT * FROM information_schema.events) for instance but that's not a problem and is
      tested.
    - check the rights with SELECT before attempting open because if we add mysql.event before
      the check the user has to have always SELECT on mysql.event to be able to use CREATE EVENT

  mysql-test/t/events.test
    1.23 06/03/26 14:22:12 andrey@lmy004. +5 -4
    - add test for subqueries
    - due to late checking of the values EVERY NULL SECOND is now a syntax error

  mysql-test/r/events.result
    1.28 06/03/26 14:22:12 andrey@lmy004. +5 -3
    update result

# 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-bug17494

--- 1.309/sql/sql_base.cc	2006-02-27 18:11:46 +01:00
+++ 1.310/sql/sql_base.cc	2006-03-26 14:22:12 +02:00
@@ -2917,6 +2917,7 @@ static bool check_lock_and_start_stmt(TH
 {
   int error;
   DBUG_ENTER("check_lock_and_start_stmt");
+  DBUG_PRINT("enter", ("table=0xlx LOCK=%d", table, lock_type));
 
   if ((int) lock_type >= (int) TL_WRITE_ALLOW_READ &&
       (int) table->reginfo.lock_type < (int) TL_WRITE_ALLOW_READ)

--- 1.171/sql/sql_lex.cc	2006-02-09 11:34:36 +01:00
+++ 1.172/sql/sql_lex.cc	2006-03-26 14:22:13 +02:00
@@ -178,6 +178,7 @@ void lex_start(THD *thd, const uchar *bu
   lex->proc_list.first= 0;
   lex->query_tables_own_last= 0;
   lex->escape_used= lex->et_compile_phase= FALSE;
+  lex->command_forbid_subselect= false;
 
   lex->name= 0;
   lex->et= NULL;

--- 1.217/sql/sql_lex.h	2006-02-28 18:33:25 +01:00
+++ 1.218/sql/sql_lex.h	2006-03-26 14:22:13 +02:00
@@ -859,6 +859,14 @@ typedef struct st_lex
   uint fk_delete_opt, fk_update_opt, fk_match_option;
   uint slave_thd_opt, start_transaction_opt;
   int nest_level;
+
+  /*
+    Usually `expr` rule of yacc is quite reused but some commands better
+    not support subqueries which comes standard with this rule, like
+    KILL, HA_OPEN, CREATE/ALTER EVENT etc. Set this to `true` to get
+    syntax error back.
+  */
+  bool command_forbid_subselect;
   /*
     In LEX representing update which were transformed to multi-update
     stores total number of tables. For LEX representing multi-delete

--- 1.526/sql/sql_parse.cc	2006-03-01 21:39:23 +01:00
+++ 1.527/sql/sql_parse.cc	2006-03-26 14:22:13 +02:00
@@ -3780,7 +3780,7 @@ end_with_restore_list:
         res= -1;
         break;
       }
-
+      
       switch (lex->sql_command) {
       case SQLCOM_CREATE_EVENT:
         res= evex_create_event(thd, lex->et, (uint) lex->create_info.options,

--- 1.315/sql/sql_show.cc	2006-02-28 18:33:25 +01:00
+++ 1.316/sql/sql_show.cc	2006-03-26 14:22:13 +02:00
@@ -1535,7 +1535,7 @@ int fill_schema_processlist(THD* thd, TA
   bool verbose;
   ulong max_query_length;
   time_t now= time(0);
-  DBUG_ENTER("fill_process_list");
+  DBUG_ENTER("fill_schema_processlist");
 
   user= thd->security_ctx->master_access & PROCESS_ACL ?
         NullS : thd->security_ctx->priv_user;
@@ -1566,6 +1566,8 @@ int fill_schema_processlist(THD* thd, TA
       val= tmp_sctx->user ? tmp_sctx->user :
             (tmp->system_thread ? "system user" : "unauthenticated user");
       table->field[1]->store(val, strlen(val), cs);
+      DBUG_PRINT("info", ("thd_id=[%lu] user=[%s] db=[%s]",
+                           tmp->thread_id, val,tmp->db?tmp->db:"NULL"));
       /* HOST */
       if (tmp->peer_port && (tmp_sctx->host || tmp_sctx->ip) &&
           thd->security_ctx->host_or_ip[0])
@@ -1574,10 +1576,15 @@ int fill_schema_processlist(THD* thd, TA
         my_snprintf(host, LIST_PROCESS_HOST_LEN, "%s:%u",
                     tmp_sctx->host_or_ip, tmp->peer_port);
         table->field[2]->store(host, strlen(host), cs);
+        DBUG_PRINT("info", ("host=%s", host));
       }
       else
+      {
+        DBUG_PRINT("info", ("host=%s", tmp_sctx->host_or_ip));
         table->field[2]->store(tmp_sctx->host_or_ip,
                                strlen(tmp_sctx->host_or_ip), cs);
+      }
+
       /* DB */
       if (tmp->db)
       {
@@ -1591,8 +1598,13 @@ int fill_schema_processlist(THD* thd, TA
       if ((val= (char *) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0)))
         table->field[4]->store(val, strlen(val), cs);
       else
+      {
+        DBUG_PRINT("info",("command=[%*s]",command_name[tmp->command].length,
+                            command_name[tmp->command].str));
         table->field[4]->store(command_name[tmp->command].str,
                                command_name[tmp->command].length, cs);
+      }
+
       /* TIME */
       table->field[5]->store((uint32)(tmp->start_time ?
                                       now - tmp->start_time : 0), TRUE);
@@ -1613,6 +1625,7 @@ int fill_schema_processlist(THD* thd, TA
 #endif
       if (val)
       {
+        DBUG_PRINT("info", ("state=%s", val));
         table->field[6]->store(val, strlen(val), cs);
         table->field[6]->set_notnull();
       }
@@ -1623,6 +1636,7 @@ int fill_schema_processlist(THD* thd, TA
       /* INFO */
       if (tmp->query)
       {
+        DBUG_PRINT("info",("query=[%*s]",min(500,tmp->query_length),tmp->query));
         table->field[7]->store(tmp->query,
                                min(max_query_length, tmp->query_length), cs);
         table->field[7]->set_notnull();

--- 1.471/sql/sql_yacc.yy	2006-03-01 21:39:23 +01:00
+++ 1.472/sql/sql_yacc.yy	2006-03-26 14:22:13 +02:00
@@ -770,7 +770,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 	signed_literal now_or_signed_literal opt_escape
 	sp_opt_default
 	simple_ident_nospvar simple_ident_q
-        field_or_var limit_option
+        field_or_var limit_option ev_starts ev_ends
         part_func_expr
 
 %type <item_num>
@@ -1317,7 +1317,11 @@ create:
 	    YYTHD->client_capabilities |= $<ulong_num>4;
 	    sp->restore_thd_mem_root(YYTHD);
 	  }
-	| CREATE EVENT_SYM opt_if_not_exists sp_name
+       | CREATE EVENT_SYM
+         {
+           Lex->command_forbid_subselect= true;
+         }
+         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
@@ -1336,7 +1340,7 @@ create:
               YYABORT;
             }
 
-            lex->create_info.options= $3;
+            lex->create_info.options= $4;
 
             if (!(lex->et= new Event_timed())) // implicitly calls Event_timed::init()
               YYABORT;
@@ -1351,7 +1355,7 @@ create:
 
             if (!lex->et_compile_phase)
             {
-              lex->et->init_name(YYTHD, $4);
+              lex->et->init_name(YYTHD, $5);
               lex->et->init_definer(YYTHD);
             }
           }
@@ -1365,13 +1369,22 @@ 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
+              $3 - block setting forbidden subselect
+              $4 - opt_if_not_exists
+              $5 - sp_name
+              $6 - the block above (where options are preserved)
             */
-            YYTHD->client_capabilities |= $<ulong_num>5;
+            YYTHD->client_capabilities |= $<ulong_num>6;
 
             /*
+              this initialization is needed because in subselect
+              if not initted this gets dangling. subselects are
+              currently forbidden for create/alter event though.
+            */
+            Lex->select_lex.db= NULL;
+            /* defensive */
+            Lex->command_forbid_subselect= false;
+            /*
               sql_command is set here because some rules in ev_sql_stmt
               can overwrite it
             */
@@ -1402,53 +1415,27 @@ create:
 	;
 
 
-ev_schedule_time: EVERY_SYM expr interval
-	  {
-            LEX *lex=Lex;
+ev_schedule_time: EVERY_SYM expr interval ev_starts ev_ends
+          {
+            LEX *lex= Lex;
             if (!lex->et_compile_phase)
             {
-              switch (lex->et->init_interval(YYTHD , $2, $3)) {
-              case EVEX_PARSE_ERROR:
-                yyerror(ER(ER_SYNTAX_ERROR));
-                YYABORT;
-                break;
-              case EVEX_BAD_PARAMS:
-                my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
-              case EVEX_MICROSECOND_UNSUP:
+              if (lex->et->is_valid_interval_type($3))
+              {
                 my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
                 YYABORT;
-                break;
               }
+              lex->et->parse_items.interval_expr= $2;
+              lex->et->interval= $3;
+              lex->et->parse_items.starts= $4;
+              lex->et->parse_items.ends= $5;
             }
           }
-          ev_starts
-          ev_ends
         | AT_SYM expr
           {
             LEX *lex=Lex;
             if (!lex->et_compile_phase)
-            {
-              switch (lex->et->init_execute_at(YYTHD, $2)) {
-              case EVEX_PARSE_ERROR:
-                yyerror(ER(ER_SYNTAX_ERROR));
-                YYABORT;  
-                break;
-              case ER_WRONG_VALUE:
-                {
-                  char buff[120];
-                  String str(buff,(uint32) sizeof(buff), system_charset_info);
-                  String *str2= $2->val_str(&str);
-                  my_error(ER_WRONG_VALUE, MYF(0), "AT",
-                           str2? str2->c_ptr():"NULL");
-                  YYABORT;
-                  break;
-                }
-              case EVEX_BAD_PARAMS:
-                my_error(ER_EVENT_EXEC_TIME_IN_THE_PAST, MYF(0));
-                YYABORT;
-                break;
-              }
-            }
+              lex->et->parse_items.execute_at= $2;
           }
       ;
 
@@ -1472,51 +1459,18 @@ opt_ev_status: /* empty */ { $$= 0; }
 
 ev_starts: /* empty */
           {
-            Lex->et->init_starts(YYTHD, new Item_func_now_local());
+            $$= new Item_func_now_local();
           }
         | STARTS_SYM expr
           {
-            LEX *lex= Lex;
-            if (!lex->et_compile_phase)
-            {
-
-              switch (lex->et->init_starts(YYTHD, $2)) {
-              case EVEX_PARSE_ERROR:
-                yyerror(ER(ER_SYNTAX_ERROR));
-                YYABORT;
-                break;
-              case EVEX_BAD_PARAMS:
-                {
-                  char buff[20];
-                  String str(buff,(uint32) sizeof(buff), system_charset_info);
-                  String *str2= $2->val_str(&str);
-                  my_error(ER_WRONG_VALUE, MYF(0), "STARTS", str2? str2->c_ptr():
-                                                                   NULL);
-                  YYABORT;
-                  break;
-                }
-              }
-            }
+            $$= $2;
           }
       ;
 
-ev_ends: /* empty */
+ev_ends: /* empty */ { $$= NULL;}
         | ENDS_SYM expr
           {
-            LEX *lex= Lex;
-            if (!lex->et_compile_phase)
-            {
-              switch (lex->et->init_ends(YYTHD, $2)) {
-              case EVEX_PARSE_ERROR:
-                yyerror(ER(ER_SYNTAX_ERROR));
-                YYABORT;
-                break;
-              case EVEX_BAD_PARAMS:
-                my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0));
-                YYABORT;
-                break;
-              }
-            }
+            $$= $2;
           }
       ;
 
@@ -4836,6 +4790,7 @@ alter:
               YYABORT;
             }
             lex->spname= 0;//defensive programming
+            lex->command_forbid_subselect= true;
 
             if (!(et= new Event_timed()))// implicitly calls Event_timed::init()
               YYABORT;
@@ -4870,14 +4825,23 @@ alter:
             YYTHD->client_capabilities |= $<ulong_num>4;
 
             /*
-              sql_command is set here because some rules in ev_sql_stmt
-              can overwrite it
+              this initialization is needed because in subselect
+              if not initted this gets dangling. subselects are
+              currently forbidden for create/alter event though.
             */
+            Lex->select_lex.db= 0;
+            /* defensive */
+            Lex->command_forbid_subselect= false;
+
             if (!($5 || $6 || $7 || $8 || $9))
             {
 	      yyerror(ER(ER_SYNTAX_ERROR));
               YYABORT;
             }
+            /*
+              sql_command is set here because some rules in ev_sql_stmt
+              can overwrite it
+            */
             Lex->sql_command= SQLCOM_ALTER_EVENT;
           }
         | ALTER TABLESPACE alter_tablespace_info
@@ -7150,9 +7114,7 @@ select_derived2:
         {
 	  LEX *lex= Lex;
 	  lex->derived_tables|= DERIVED_SUBQUERY;
-	  if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN &&
-	       lex->sql_command <= (int)SQLCOM_HA_READ) ||
-	       lex->sql_command == (int)SQLCOM_KILL)
+	  if (lex->command_forbid_subselect)
 	  {
 	    yyerror(ER(ER_SYNTAX_ERROR));
 	    YYABORT;
@@ -8647,11 +8609,16 @@ purge_option:
 /* kill threads */
 
 kill:
-	KILL_SYM kill_option expr
+	KILL_SYM
+        {
+          Lex->command_forbid_subselect= true;
+        }
+        kill_option expr
 	{
 	  LEX *lex=Lex;
 	  lex->value_list.empty();
-	  lex->value_list.push_front($3);
+	  lex->value_list.push_front($4);
+          lex->command_forbid_subselect= true;
           lex->sql_command= SQLCOM_KILL;
 	};
 
@@ -10087,6 +10054,7 @@ handler:
 	    my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
 	    YYABORT;
 	  }
+          lex->command_forbid_subselect= true;
 	  lex->sql_command = SQLCOM_HA_OPEN;
 	  if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0))
 	    YYABORT;
@@ -10111,6 +10079,7 @@ handler:
 	    my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
 	    YYABORT;
 	  }
+          lex->command_forbid_subselect= true;
 	  lex->sql_command = SQLCOM_HA_READ;
 	  lex->ha_rkey_mode= HA_READ_KEY_EXACT;	/* Avoid purify warnings */
 	  lex->current_select->select_limit= new Item_int((int32) 1);
@@ -10739,9 +10708,7 @@ subselect_start:
 	'(' SELECT_SYM
 	{
 	  LEX *lex=Lex;
-	  if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN &&
-	       lex->sql_command <= (int)SQLCOM_HA_READ) ||
-	       lex->sql_command == (int)SQLCOM_KILL)
+          if (lex->command_forbid_subselect)
 	  {
             yyerror(ER(ER_SYNTAX_ERROR));
 	    YYABORT;

--- 1.27/mysql-test/r/events.result	2006-02-28 14:43:41 +01:00
+++ 1.28/mysql-test/r/events.result	2006-03-26 14:22:12 +02:00
@@ -1,5 +1,8 @@
 create database if not exists events_test;
+delete from mysql.event;
 use events_test;
+create event subq on schedule every (select 1 from dual) second do select 2;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select 1 from dual) second do select 2' at line 1
 CREATE USER pauline@localhost;
 CREATE DATABASE db_x;
 GRANT EVENT ON db_x.* TO pauline@localhost;
@@ -106,7 +109,6 @@ drop event if exists event3;
 Warnings:
 Note	1305	Event event3 does not exist
 create event event3 on schedule every 50 + 10 minute starts date_add("20100101", interval 5 minute) ends date_add("20151010", interval 5 day) comment "portokala_comment" DO insert into t_event3 values (unix_timestamp(), rand());
-set max_allowed_packet=128000000;
 select count(*) from t_event3;
 count(*)
 0
@@ -365,9 +367,9 @@ db	name	body	definer	convert_tz(execute_
 events_test	e_26	set @a = 5	root@localhost	2017-01-01 00:00:00	DROP
 drop event e_26;
 create event e_26 on schedule at NULL disabled do set @a = 5;
-ERROR HY000: Incorrect AT value: 'NULL'
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'disabled do set @a = 5' at line 1
 create event e_26 on schedule at 'definitely not a datetime' disabled do set @a = 5;
-ERROR HY000: Incorrect AT value: 'definitely not a datetime'
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'disabled do set @a = 5' at line 1
 set names utf8;
 create event задачка on schedule every 123 minute starts now() ends now() + interval 1 month do select 1;
 drop event задачка;

--- 1.22/mysql-test/t/events.test	2006-02-28 11:46:00 +01:00
+++ 1.23/mysql-test/t/events.test	2006-03-26 14:22:12 +02:00
@@ -1,6 +1,8 @@
 create database if not exists events_test;
+delete from mysql.event;
 use events_test;
-
+--error 1064
+create event subq on schedule every (select 1 from dual) second do select 2;
 #
 # START:  BUG #17289 Events: missing privilege check for drop database
 #
@@ -101,7 +103,6 @@ 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("20100101", interval 5 minute) ends date_add("20151010", interval 5 day) comment "portokala_comment" DO insert into t_event3 values (unix_timestamp(), rand());
-set max_allowed_packet=128000000;
 select count(*) from t_event3;
 drop event event3;
 drop table t_event3;
@@ -317,9 +318,9 @@ drop event one_event;
 create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
 select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
 drop event e_26;
---error 1503
+--error 1064
 create event e_26 on schedule at NULL disabled do set @a = 5;
---error 1503
+--error 1064
 create event e_26 on schedule at 'definitely not a datetime' disabled do set @a = 5;
 
 set names utf8;

--- 1.37/sql/event.cc	2006-02-28 20:32:30 +01:00
+++ 1.38/sql/event.cc	2006-03-26 14:22:12 +02:00
@@ -463,7 +463,7 @@ common_1_lev_code:
 
 
 /*
-  Open mysql.event table for read
+  Open mysql.event table 
 
   SYNOPSIS
     evex_open_event_table_for_read()
@@ -481,7 +481,7 @@ int
 evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table)
 {
   TABLE_LIST tables;
-  DBUG_ENTER("open_proc_table");
+  DBUG_ENTER("evex_open_event_table");
 
   bzero((char*) &tables, sizeof(tables));
   tables.db= (char*) "mysql";
@@ -505,6 +505,63 @@ evex_open_event_table(THD *thd, enum thr
 
 
 /*
+  Open mysql.event table for write for CREATE/ALTER EVENT
+
+  SYNOPSIS
+    evex_open_all_tables()
+      thd         Thread context
+      lock_type   How to lock the table
+      table       The table pointer
+
+  RETURNS
+    0   OK
+    1   Error during open_n_load
+    2   mysql.event tampered
+*/
+
+static int
+evex_open_all_tables(THD *thd, TABLE **table)
+{
+  TABLE_LIST *table_list;
+  LEX_STRING dbname={(char*) STRING_WITH_LEN("mysql")};
+  LEX_STRING tname= {(char*) STRING_WITH_LEN("event")};
+
+  DBUG_ENTER("evex_open_all_tables");
+
+  Table_ident *ident= new Table_ident(thd, dbname, tname, 1);
+  /*
+    We do:
+    1. Check whether we have access to all tables found during parsing,
+       this may include mysql.event. If not then we bail out.
+    2. Once we know we have access we can add mysql.event to the list
+       of the tables needed to be open (we do open in one shot to prevent
+       deadlocks if we do open in two different steps). mysql.event is added
+       at this stage because we need it and the user may not have SELECT
+       on it.
+    3. We open the tables.
+  */
+  if (check_table_access(thd, SELECT_ACL, thd->lex->query_tables, 0) ||
+      !(table_list= thd->lex->select_lex.
+         add_table_to_list(thd, ident, 0, 0, TL_WRITE, (List<String> *) 0,
+                           (List<String> *) 0)) ||
+      open_and_lock_tables(thd, thd->lex->query_tables))
+    DBUG_RETURN(1);
+
+  /*
+    mysql.event is the first and only table on table_list, it happens to
+    be the last on thd->lex->query_tables.
+  */
+  if (table_check_intact(table_list->table, EVEX_FIELD_COUNT, event_table_fields,
+                         &mysql_event_last_create_time,
+                         ER_CANNOT_LOAD_FROM_TABLE))
+    DBUG_RETURN(2);
+
+  *table= table_list->table;
+  DBUG_RETURN(0);
+}
+
+
+/*
   Find row in open mysql.event table representing event
 
   SYNOPSIS
@@ -710,8 +767,9 @@ trunc_err:
      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
+       create_if_not   If an warning should be generated in case event exists
+       rows_affected   How many rows were affected
+       table           Table to use
 
      Return value
                         0 - OK
@@ -723,10 +781,9 @@ trunc_err:
 
 static int
 db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
-                uint *rows_affected)
+                uint *rows_affected, TABLE *table)
 {
   int ret= 0;
-  TABLE *table;
   char olddb[128];
   bool dbchanged= false;
   DBUG_ENTER("db_create_event");
@@ -734,11 +791,6 @@ db_create_event(THD *thd, Event_timed *e
 
   *rows_affected= 0;
   DBUG_PRINT("info", ("open mysql.event for update"));
-  if (evex_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))
@@ -828,15 +880,11 @@ db_create_event(THD *thd, Event_timed *e
 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);
 }
 
@@ -849,6 +897,7 @@ err:
        thd      THD
        sp_name  the name of the event to alter
        et       event's data
+       table    Table to use
 
    NOTES
      sp_name is passed since this is the name of the event to
@@ -856,10 +905,10 @@ err:
 */
 
 static int
-db_update_event(THD *thd, Event_timed *et, sp_name *new_name)
+db_update_event(THD *thd, Event_timed *et, sp_name *new_name, TABLE *table)
 {
-  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));
@@ -868,12 +917,6 @@ db_update_event(THD *thd, Event_timed *e
     DBUG_PRINT("enter", ("rename to: %.*s", new_name->m_name.length,
                                             new_name->m_name.str));
 
-  if (evex_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)
   {
@@ -881,14 +924,14 @@ db_update_event(THD *thd, Event_timed *e
         !sortcmp_lex_string(et->dbname, new_name->m_db, system_charset_info))
     {
       my_error(ER_EVENT_SAME_NAME, MYF(0), et->name.str);
-      goto err;    
+      DBUG_RETURN(EVEX_GENERAL_ERROR);
     }
   
     if (!evex_db_find_event_by_name(thd, new_name->m_db, new_name->m_name,
                                 et->definer, table))
     {
       my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str);
-      goto err;
+      DBUG_RETURN(EVEX_GENERAL_ERROR);
     }  
   }
   /*
@@ -900,7 +943,7 @@ db_update_event(THD *thd, Event_timed *e
   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;
+    DBUG_RETURN(EVEX_GENERAL_ERROR);
   }
 
   store_record(table,record[1]);
@@ -910,7 +953,7 @@ db_update_event(THD *thd, Event_timed *e
 
   /* 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;
+    DBUG_RETURN(EVEX_GENERAL_ERROR);
 
   if (new_name)
   {    
@@ -923,17 +966,10 @@ db_update_event(THD *thd, Event_timed *e
   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;
+    DBUG_RETURN(EVEX_GENERAL_ERROR);
   }
 
-  /* 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);
 }
 
 
@@ -962,7 +998,7 @@ db_find_event(THD *thd, sp_name *name, L
   int ret;
   Event_timed *et=NULL;
   DBUG_ENTER("db_find_event");
-  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+  DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
 
   if (!root)
     root= &evex_mem_root;
@@ -1036,7 +1072,7 @@ evex_load_and_compile_event(THD * thd, s
   Open_tables_state backup;
 
   DBUG_ENTER("db_load_and_compile_event");
-  DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
+  DBUG_PRINT("enter", ("name: %.*s", spn->m_name.length, spn->m_name.str));
 
   tmp_mem_root= thd->mem_root;
   thd->mem_root= &evex_mem_root;
@@ -1152,6 +1188,82 @@ done:
 
 
 /*
+   Check params which we got from the parsing phase.
+
+   SYNOPSIS
+     evex_check_timing_params()
+       thd            THD
+       et             event's data
+   
+   RETURNS
+     0                OK
+     EVEX_BAD_PARAMS  Error
+  
+   REMARKS
+     Issues error messages
+*/
+
+static
+int evex_check_timing_params(THD *thd, Event_timed *et)
+{
+  const char *pos= NULL;
+  Item *bad_item;
+
+  DBUG_ENTER("evex_check_timing_params");
+  DBUG_PRINT("info", ("execute_at=0x%d expr=0x%d starts=0x%d ends=0x%d",
+                      et->parse_items.execute_at, et->parse_items.interval_expr,
+                      et->parse_items.starts, et->parse_items.ends));
+
+  if (et->parse_items.execute_at)
+  {
+    DBUG_PRINT("info", ("ONE TIME"));
+    if (et->init_execute_at(thd, et->parse_items.execute_at))
+    {
+      pos= "AT";
+      bad_item= et->parse_items.execute_at;
+      goto wrong_value;
+    }
+  }
+  else
+  {
+    DBUG_PRINT("info", ("RECURRING"));
+    if (et->parse_items.interval_expr &&
+        et->init_interval(thd, et->parse_items.interval_expr, et->interval))
+    {
+      pos= "INTERVAL";
+      bad_item= et->parse_items.interval_expr;
+      goto wrong_value;
+    }
+
+    if (et->parse_items.starts && et->init_starts(thd, et->parse_items.starts))
+    {
+      pos= "STARTS";
+      bad_item= et->parse_items.starts;
+      goto wrong_value;
+    }
+
+    if (et->parse_items.ends && et->init_ends(thd, et->parse_items.ends))
+    {
+      /*
+        despite the error name the value is
+        eng "ENDS is either invalid or before STARTS"
+      */
+      my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0));
+      DBUG_RETURN(EVEX_BAD_PARAMS);
+    }
+  }
+  DBUG_RETURN(0);
+wrong_value:
+  {
+    char buff[120];
+    String str(buff,(uint32) sizeof(buff), system_charset_info);
+    String *str2= bad_item->fixed? bad_item->val_str(&str):NULL;
+    my_error(ER_WRONG_VALUE, MYF(0), pos, str2? str2->c_ptr():"NULL");
+    DBUG_RETURN(EVEX_BAD_PARAMS);
+  }
+}
+
+/*
    The function exported to the world for creating of events.
 
    SYNOPSIS
@@ -1172,14 +1284,22 @@ evex_create_event(THD *thd, Event_timed 
                   uint *rows_affected)
 {
   int ret = 0;
+  TABLE *table;
 
   DBUG_ENTER("evex_create_event");
-  DBUG_PRINT("enter", ("name: %*s options:%d", et->name.length,
+  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= evex_open_all_tables(thd, &table)))
+    DBUG_RETURN(ret);
+
+  if ((ret= evex_check_timing_params(thd, et)))
+    goto done;
+
+  ret = db_create_event(thd, et, create_options & HA_LEX_CREATE_IF_NOT_EXISTS,
+                        rows_affected, table);
+  close_thread_tables(thd);
+  if (ret)
     goto done;
 
   VOID(pthread_mutex_lock(&LOCK_evex_running));
@@ -1217,17 +1337,23 @@ evex_update_event(THD *thd, Event_timed 
                   uint *rows_affected)
 {
   int ret;
-  bool need_second_pass= true;
+  TABLE *table;
 
   DBUG_ENTER("evex_update_event");
-  DBUG_PRINT("enter", ("name: %*s", et->name.length, et->name.str));
+  DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
+
+  if ((ret= evex_open_all_tables(thd, &table)))
+    DBUG_RETURN(ret);
+
+  if ((ret= evex_check_timing_params(thd, et)))
+    goto done;
 
   /*
     db_update_event() opens & closes the table to prevent
     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_update_event(thd, et, new_name, table)))
     goto done;
 
   VOID(pthread_mutex_lock(&LOCK_evex_running));
@@ -1337,7 +1463,6 @@ evex_drop_event(THD *thd, Event_timed *e
 
   DBUG_ENTER("evex_drop_event");
 
-
   VOID(pthread_mutex_lock(&LOCK_evex_running));
   if (evex_is_running)
     ret= evex_remove_from_cache(&et->dbname, &et->name, true, true);
@@ -1376,7 +1501,7 @@ evex_show_create_event(THD *thd, sp_name
   Open_tables_state backup;
 
   DBUG_ENTER("evex_update_event");
-  DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
+  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, &definer, &et, NULL, thd->mem_root);

--- 1.26/sql/event.h	2006-02-28 18:33:25 +01:00
+++ 1.27/sql/event.h	2006-03-26 14:22:12 +02:00
@@ -87,8 +87,17 @@ class Event_timed
 
   bool status_changed;
   bool last_executed_changed;
+  
 
 public:
+  struct parse_items
+  {
+    Item *execute_at;
+    Item *interval_expr;
+    Item *starts;
+    Item *ends;
+  } parse_items;
+
   TIME last_executed;
 
   LEX_STRING dbname;
@@ -124,7 +133,8 @@ public:
 
   Event_timed():in_spawned_thread(0),locked_by_thread_id(0),
                 running(0), status_changed(false),
-                last_executed_changed(false), expression(0), created(0),
+                last_executed_changed(false),
+                expression(0), created(0),
                 modified(0), on_completion(MYSQL_EVENT_ON_COMPLETION_DROP),
                 status(MYSQL_EVENT_ENABLED), sphead(0), sql_mode(0), 
                 body_begin(0), dropped(false),
@@ -152,6 +162,9 @@ public:
   int
   init_execute_at(THD *thd, Item *expr);
 
+  static int
+  is_valid_interval_type(interval_type new_interval);
+  
   int
   init_interval(THD *thd, Item *expr, interval_type new_interval);
 

--- 1.41/sql/event_executor.cc	2006-03-01 04:21:57 +01:00
+++ 1.42/sql/event_executor.cc	2006-03-26 14:22:12 +02:00
@@ -206,6 +206,7 @@ init_events()
   {
 #ifndef DBUG_FAULTY_THR
     /* TODO Andrey: Change the error code returned! */
+    DBUG_PRINT("info", ("fork main thread"));
     if (pthread_create(&th, &connection_attrib, event_executor_main,(void*)NULL))
       DBUG_RETURN(ER_SLAVE_THREAD);
 #else
@@ -352,6 +353,8 @@ executor_wait_till_next_event_exec(THD *
   VOID(pthread_mutex_unlock(&LOCK_event_arrays));
 
   DBUG_PRINT("evex main thread",("unlocked LOCK_event_arrays"));
+  /* count the time in 0.05s */
+  t2sleep*=20;
   if (t2sleep > 0)
   {
     ulonglong modified= et->modified;
@@ -365,8 +368,12 @@ executor_wait_till_next_event_exec(THD *
             evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*)->modified ==
              modified))
     {
-      DBUG_PRINT("evex main thread",("will sleep a bit more."));
-      my_sleep(1000000);
+      if (!(t2sleep % 10))
+      {
+        /* Don't sleep too much. We should catch changes quickly. */
+        DBUG_PRINT("evex main thread",("will sleep a bit more."));
+      }
+      my_sleep(50000);
     }
     DBUG_PRINT("info",("saved_modified=%llu current=%llu", modified,
                evex_queue_num_elements(EVEX_EQ_NAME)? 
@@ -382,6 +389,7 @@ executor_wait_till_next_event_exec(THD *
   if (thd->killed && event_executor_running_global_var)
     ret= WAIT_STATUS_STOP_EXECUTOR;
 
+  DBUG_PRINT("info", ("retcode=%d", ret));
   DBUG_RETURN(ret);
 }
 
@@ -407,6 +415,7 @@ event_executor_main(void *arg)
   THD *thd;			/* needs to be first for thread_stack */
   uint i=0, j=0;
   my_ulonglong cnt= 0;
+  int ret;
 
   DBUG_ENTER("event_executor_main");
   DBUG_PRINT("event_executor_main", ("EVEX thread started"));
@@ -451,6 +460,8 @@ event_executor_main(void *arg)
   thread_running++;
   VOID(pthread_mutex_unlock(&LOCK_thread_count));
 
+  DBUG_PUSH(IF_WIN("d:t:T:i:A,\\mysqld.trace",
+                   "d:t:T:i:A,/tmp/mysqld.trace"));
   DBUG_PRINT("EVEX main thread", ("Initing events_queue"));
 
   /*
@@ -464,7 +475,12 @@ event_executor_main(void *arg)
   evex_is_running= true;  
   VOID(pthread_mutex_unlock(&LOCK_evex_running));
 
-  thd->security_ctx->user= my_strdup("event_scheduler", MYF(0));
+  /*
+    set priv_user to not core if there is a trigger on mysql.event
+    prevents from core on scheduler start-up.
+  */
+  thd->security_ctx->user= thd->security_ctx->priv_user=
+    my_strdup("event_scheduler", MYF(0));
 
   if (evex_load_events_from_db(thd))
     goto finish;
@@ -489,7 +505,7 @@ event_executor_main(void *arg)
 
     if (!evex_queue_num_elements(EVEX_EQ_NAME))
     {
-      my_sleep(1000000);// sleep 1s
+      my_sleep(100000);// sleep 0.1s
       continue;
     }
 
@@ -552,7 +568,11 @@ restart_ticking:
       DBUG_PRINT("evex main thread", ("[%10s] next exec at [%llu]", et->name.str,
                                TIME_to_ulonglong_datetime(&et->execute_at)));
 
-      et->update_fields(thd);
+      if ((ret= et->update_fields(thd)))
+      {
+        sql_print_error("SCHEDULER: Error while update_fields. Code=%d", ret);
+        UNLOCK_MUTEX_AND_BAIL_OUT(LOCK_event_arrays, finish);
+      }
 #ifndef DBUG_FAULTY_THR
       thread_safe_increment(workers_count, &LOCK_workers_count);
       switch ((fork_ret_code= et->spawn_now(event_executor_worker))) {
@@ -590,7 +610,7 @@ restart_ticking:
     VOID(pthread_mutex_unlock(&LOCK_event_arrays));
   }/* while */
 finish:
-
+  DBUG_PRINT("evex main thread", ("After main loop. Stopping."));
   /* First manifest that this thread does not work and then destroy */
   VOID(pthread_mutex_lock(&LOCK_evex_running));
   evex_is_running= false;
@@ -862,7 +882,7 @@ evex_load_events_from_db(THD *thd)
     DBUG_PRINT("evex_load_events_from_db", ("Adding to the exec list."));
 
     evex_queue_insert(&EVEX_EQ_NAME, (EVEX_PTOQEL) et);
-    DBUG_PRINT("evex_load_events_from_db", ("%p %*s",
+    DBUG_PRINT("evex_load_events_from_db", ("%p %.*s",
                 et, et->name.length,et->name.str));
     count++;
   }
@@ -904,6 +924,11 @@ sys_var_event_executor::update(THD *thd,
 {
   /* here start the thread if not running. */
   DBUG_ENTER("sys_var_event_executor::update");
+  {
+    ulonglong __t= my_getsystime();
+    DBUG_PRINT("info", ("tv.sec=%llu tv.usec=%llu", __t/10000000,
+                        (__t%10000000)/10));
+  }
   VOID(pthread_mutex_lock(&LOCK_evex_running));
   *value= var->save_result.ulong_value;
 
@@ -979,7 +1004,7 @@ evex_print_warnings(THD *thd, Event_time
     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_xxx_handlers[err->level])("%.*s", err_msg.length(), err_msg.c_ptr());
   }
 
 

--- 1.45/sql/event_timed.cc	2006-03-02 21:01:56 +01:00
+++ 1.46/sql/event_timed.cc	2006-03-26 14:22:12 +02:00
@@ -47,6 +47,8 @@ Event_timed::init()
   definer_user.length= definer_host.length= 0;
 
   sql_mode= 0;
+  parse_items.execute_at= parse_items.interval_expr= parse_items.starts=
+    parse_items.ends= NULL;
 
   DBUG_VOID_RETURN;
 }
@@ -155,7 +157,10 @@ Event_timed::init_execute_at(THD *thd, I
   DBUG_ENTER("Event_timed::init_execute_at");
 
   if (expr->fix_fields(thd, &expr))
-    DBUG_RETURN(EVEX_PARSE_ERROR);
+  {
+    DBUG_PRINT("error", ("fix_fields failed"));
+    DBUG_RETURN(EVEX_BAD_PARAMS);
+  }
   
   /* no starts and/or ends in case of execute_at */
   DBUG_PRINT("info", ("starts_null && ends_null should be 1 is %d",
@@ -167,11 +172,14 @@ Event_timed::init_execute_at(THD *thd, I
                                             (my_time_t) thd->query_start());
 
   if ((not_used= expr->get_date(&ltime, TIME_NO_ZERO_DATE)))
-    DBUG_RETURN(ER_WRONG_VALUE);
+    DBUG_RETURN(EVEX_BAD_PARAMS);
 
   if (TIME_to_ulonglong_datetime(&ltime) <
       TIME_to_ulonglong_datetime(&time_tmp))
+  {
+    my_error(ER_EVENT_EXEC_TIME_IN_THE_PAST, MYF(0));
     DBUG_RETURN(EVEX_BAD_PARAMS);
+  }
 
 
   /*
@@ -187,7 +195,55 @@ Event_timed::init_execute_at(THD *thd, I
 
 
 /*
-  Set time for execution for transient events.
+  Checks whether we support the interval type
+
+  SYNOPSIS
+    Event_timed::is_valid_interval_type()
+      new_interval  what is the interval
+
+  RETURNS
+    0                       OK
+    EVEX_MICROSECOND_UNSUP  Microseconds are not supported.
+*/
+
+int
+Event_timed::is_valid_interval_type(interval_type new_interval)
+{
+  DBUG_ENTER("Event_timed::is_valid_interval_type");
+  switch (new_interval) {
+  case INTERVAL_MICROSECOND:
+  case INTERVAL_SECOND_MICROSECOND:
+  case INTERVAL_MINUTE_MICROSECOND:
+  case INTERVAL_HOUR_MICROSECOND:
+  case INTERVAL_DAY_MICROSECOND:
+    DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
+#ifndef DBUG_OFF
+  case INTERVAL_YEAR:
+  case INTERVAL_QUARTER:
+  case INTERVAL_MONTH:
+  case INTERVAL_WEEK:
+  case INTERVAL_DAY:
+  case INTERVAL_HOUR:
+  case INTERVAL_MINUTE:
+  case INTERVAL_SECOND:
+  case INTERVAL_YEAR_MONTH:
+  case INTERVAL_DAY_HOUR:
+  case INTERVAL_DAY_MINUTE:
+  case INTERVAL_HOUR_MINUTE:
+  case INTERVAL_HOUR_SECOND:
+  case INTERVAL_MINUTE_SECOND:
+  case INTERVAL_DAY_SECOND:
+    DBUG_RETURN(0);
+  default:
+    DBUG_PRINT("error", ("type %d is unknown", (int) new_interval));
+    DBUG_ASSERT(0);
+#endif  
+  }
+}
+
+
+/*
+  Set time for execution for reccuring events.
 
   SYNOPSIS
     Event_timed::init_interval()
@@ -210,11 +266,14 @@ Event_timed::init_interval(THD *thd, Ite
   DBUG_ENTER("Event_timed::init_interval");
 
   if (expr->fix_fields(thd, &expr))
-    DBUG_RETURN(EVEX_PARSE_ERROR);
+    DBUG_RETURN(EVEX_BAD_PARAMS);
 
   value.alloc(MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN);
   if (get_interval_value(expr, new_interval, &value, &interval))
-    DBUG_RETURN(EVEX_PARSE_ERROR);
+  {
+    DBUG_PRINT("error", ("fix_fields failed"));
+    DBUG_RETURN(EVEX_BAD_PARAMS);
+  }
 
   expression= 0;
 
@@ -250,17 +309,21 @@ Event_timed::init_interval(THD *thd, Ite
     break;
   case INTERVAL_HOUR_SECOND: /* day is anyway 0 */
   case INTERVAL_DAY_SECOND:
-    /* DAY_SECOND having problems because of leap seconds? */
+    /* QQ: DAY_SECOND having problems because of leap seconds? */
     expression= ((interval.day* 24 + interval.hour) * 60 + interval.minute)*60
                  + interval.second;
     break;
   case INTERVAL_MINUTE_MICROSECOND: /* day and hour are 0 */
   case INTERVAL_HOUR_MICROSECOND:   /* day is anyway 0    */
   case INTERVAL_DAY_MICROSECOND:
-    DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
+    DBUG_ASSERT(0);
+    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
+    DBUG_RETURN(EVEX_MICROSECOND_UNSUP);  
+#ifdef WE_SUPPORT_MICROSEC
     expression= ((((interval.day*24) + interval.hour)*60+interval.minute)*60 +
                 interval.second) * 1000000L + interval.second_part;
     break;
+#endif
   case INTERVAL_HOUR_MINUTE:
     expression= interval.hour * 60 + interval.minute;
     break;
@@ -268,13 +331,19 @@ Event_timed::init_interval(THD *thd, Ite
     expression= interval.minute * 60 + interval.second;
     break;
   case INTERVAL_SECOND_MICROSECOND:
-    DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
+    DBUG_ASSERT(0);
+    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
+    DBUG_RETURN(EVEX_MICROSECOND_UNSUP);  
+#ifdef WE_SUPPORT_MICROSEC
     expression= interval.second * 1000000L + interval.second_part;
     break;
+#endif
   case INTERVAL_MICROSECOND:
+    DBUG_ASSERT(0);
+    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
     DBUG_RETURN(EVEX_MICROSECOND_UNSUP);  
   }
-  if (interval.neg || expression > EVEX_MAX_INTERVAL_VALUE)
+  if (interval.neg || expression > EVEX_MAX_INTERVAL_VALUE || !expression)
     DBUG_RETURN(EVEX_BAD_PARAMS);
 
   this->interval= new_interval;
@@ -307,25 +376,21 @@ int
 Event_timed::init_starts(THD *thd, Item *new_starts)
 {
   my_bool not_used;
-  TIME ltime, time_tmp;
+  TIME ltime, ltime_now;
 
   DBUG_ENTER("Event_timed::init_starts");
 
   if (new_starts->fix_fields(thd, &new_starts))
-    DBUG_RETURN(EVEX_PARSE_ERROR);
+  {
+    DBUG_PRINT("error", ("fix_fields failed"));
+    DBUG_RETURN(EVEX_BAD_PARAMS);
+  }
 
   if ((not_used= new_starts->get_date(&ltime, TIME_NO_ZERO_DATE)))
     DBUG_RETURN(EVEX_BAD_PARAMS);
 
   /* Let's check whether time is in the past */
-  thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,
-                                            (my_time_t) thd->query_start());
-
-  DBUG_PRINT("info",("now   =%lld", TIME_to_ulonglong_datetime(&time_tmp)));
-  DBUG_PRINT("info",("starts=%lld", TIME_to_ulonglong_datetime(&ltime)));
-  if (TIME_to_ulonglong_datetime(&ltime) <
-      TIME_to_ulonglong_datetime(&time_tmp))
-    DBUG_RETURN(EVEX_BAD_PARAMS);
+  my_tz_UTC->gmt_sec_to_TIME(&ltime_now, (my_time_t) (thd->query_start()));
 
   /*
     This may result in a 1970-01-01 date if ltime is > 2037-xx-xx
@@ -333,6 +398,12 @@ Event_timed::init_starts(THD *thd, Item 
   */
   my_tz_UTC->gmt_sec_to_TIME(&ltime, TIME_to_timestamp(thd, &ltime, &not_used));
 
+  DBUG_PRINT("info",("NOW   =%lld", TIME_to_ulonglong_datetime(&ltime_now)));
+  DBUG_PRINT("info",("STARTS=%lld", TIME_to_ulonglong_datetime(&ltime)));
+  if (TIME_to_ulonglong_datetime(&ltime) <
+      TIME_to_ulonglong_datetime(&ltime_now))
+    DBUG_RETURN(EVEX_BAD_PARAMS);
+
   starts= ltime;
   starts_null= FALSE;
   DBUG_RETURN(0);
@@ -370,22 +441,34 @@ Event_timed::init_ends(THD *thd, Item *n
   DBUG_ENTER("Event_timed::init_ends");
 
   if (new_ends->fix_fields(thd, &new_ends))
+  {
+    DBUG_PRINT("error", ("fix_fields failed"));
     DBUG_RETURN(EVEX_PARSE_ERROR);
+  }
 
   DBUG_PRINT("info", ("convert to TIME"));
   if ((not_used= new_ends->get_date(&ltime, TIME_NO_ZERO_DATE)))
+  {
+    DBUG_PRINT("error", ("get_date returned error"));
     DBUG_RETURN(EVEX_BAD_PARAMS);
+  }
+
+  DBUG_PRINT("info", ("ENDS  =%lld", TIME_to_ulonglong_datetime(&ltime)));
 
-  /*
-    This may result in a 1970-01-01 date if ltime is > 2037-xx-xx ?
-    CONVERT_TZ has similar problem ?
-  */
   DBUG_PRINT("info", ("get the UTC time"));
   my_tz_UTC->gmt_sec_to_TIME(&ltime, TIME_to_timestamp(thd, &ltime, &not_used));
 
-  /* Check whether ends is after starts */
+  DBUG_PRINT("info", ("STARTS=%lld", TIME_to_ulonglong_datetime(&starts)));
+  DBUG_PRINT("info", ("ENDS  =%lld", TIME_to_ulonglong_datetime(&ltime)));
+
   DBUG_PRINT("info", ("ENDS after STARTS?"));
-  if (!starts_null && my_time_compare(&starts, &ltime) != -1)
+  /*
+    Check whether ends is after starts
+    
+    This may result in a 1970-01-01 date if ltime is > 2037-xx-xx ?
+    CONVERT_TZ has similar problem ?
+  */
+  if (!starts_null && my_time_compare(&starts, &ltime) == 1)
     DBUG_RETURN(EVEX_BAD_PARAMS);
 
   /*
@@ -393,8 +476,9 @@ Event_timed::init_ends(THD *thd, Item *n
     set before NOW() and in this case the following check should be done.
     Check whether ENDS is not in the past.
   */
+  my_tz_UTC->gmt_sec_to_TIME(&ltime_now, (my_time_t) thd->query_start());
   DBUG_PRINT("info", ("ENDS after NOW?"));
-  my_tz_UTC->gmt_sec_to_TIME(&ltime_now, thd->query_start());
+  DBUG_PRINT("info", ("NOW   =%lld", TIME_to_ulonglong_datetime(&ltime_now)));
   if (my_time_compare(&ltime_now, &ltime) == 1)
     DBUG_RETURN(EVEX_BAD_PARAMS);
 
@@ -984,7 +1068,7 @@ Event_timed::update_fields(THD *thd)
 
   DBUG_ENTER("Event_timed::update_time_fields");
 
-  DBUG_PRINT("enter", ("name: %*s", name.length, name.str));
+  DBUG_PRINT("enter", ("name: %.*s", name.length, name.str));
 
   /* No need to update if nothing has changed */
   if (!(status_changed || last_executed_changed))
@@ -1024,7 +1108,8 @@ Event_timed::update_fields(THD *thd)
     ret= EVEX_WRITE_ROW_FAILED;
 
 done:
-  close_thread_tables(thd);
+  if (table)
+    close_thread_tables(thd);
   thd->restore_backup_open_tables_state(&backup);
 
   DBUG_RETURN(ret);

--- 1.210/sql/sp_head.cc	2006-03-01 16:27:46 +01:00
+++ 1.211/sql/sp_head.cc	2006-03-26 14:22:12 +02:00
@@ -2308,12 +2308,13 @@ sp_instr_stmt::execute(THD *thd, uint *n
   if (!(res= alloc_query(thd, m_query.str, m_query.length+1)) &&
       !(res=subst_spvars(thd, this, &m_query)))
   {
+    if (unlikely((thd->options & OPTION_LOG_OFF)==0))
+      general_log_print(thd, COM_QUERY, "%*s", thd->query_length, thd->query);
+
     /*
       (the order of query cache and subst_spvars calls is irrelevant because
       queries with SP vars can't be cached)
     */
-    if (unlikely((thd->options & OPTION_LOG_OFF)==0))
-      general_log_print(thd, COM_QUERY, "%s", thd->query);
 
     if (query_cache_send_result_to_client(thd,
 					  thd->query, thd->query_length) <= 0)

--- 1.164/sql/sql_prepare.cc	2006-02-25 19:35:09 +01:00
+++ 1.165/sql/sql_prepare.cc	2006-03-26 14:22:13 +02:00
@@ -175,6 +175,7 @@ inline bool is_param_null(const uchar *p
 static Prepared_statement *
 find_prepared_statement(THD *thd, ulong id, const char *where)
 {
+  DBUG_ENTER("find_prepared_statement");
   /*
     To strictly separate namespaces of SQL prepared statements and C API
     prepared statements find() will return 0 if there is a named prepared
@@ -187,9 +188,10 @@ find_prepared_statement(THD *thd, ulong 
     char llbuf[22];
     my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), llstr(id, llbuf),
              where);
-    return 0;
+    DBUG_RETURN(0);
   }
-  return (Prepared_statement *) stmt;
+  DBUG_PRINT("info", ("stmt=0x%lx", stmt));
+  DBUG_RETURN((Prepared_statement *) stmt);
 }
 
 
@@ -1873,7 +1875,10 @@ void mysql_stmt_prepare(THD *thd, const 
     thd->stmt_map.erase(stmt);
   }
   else
+  {
+    DBUG_PRINT("info", ("prepared stmt_id [%lu]", stmt->id));
     general_log_print(thd, COM_STMT_PREPARE, "[%lu] %s", stmt->id, packet);
+  }
 
   /* check_prepared_statemnt sends the metadata packet in case of success */
   DBUG_VOID_RETURN;
@@ -2040,7 +2045,10 @@ void mysql_sql_stmt_prepare(THD *thd)
     thd->stmt_map.erase(stmt);
   }
   else
+  {
+    DBUG_PRINT("info", ("Statement prepared"));
     send_ok(thd, 0L, 0L, "Statement prepared");
+  }
 
   DBUG_VOID_RETURN;
 }
@@ -2202,7 +2210,7 @@ void mysql_stmt_execute(THD *thd, char *
   Prepared_statement *stmt;
   bool error;
   DBUG_ENTER("mysql_stmt_execute");
-
+  DBUG_PRINT("enter",("stmt_id=[%lu]", stmt_id));
   packet+= 9;                               /* stmt_id + 5 bytes of flags */
 
   /* First of all clear possible warnings from the previous command */
@@ -2332,6 +2340,7 @@ void mysql_stmt_fetch(THD *thd, char *pa
   Statement stmt_backup;
   Server_side_cursor *cursor;
   DBUG_ENTER("mysql_stmt_fetch");
+  DBUG_PRINT("enter", ("stmt_id=[%lu]", stmt_id));
 
   /* First of all clear possible warnings from the previous command */
   mysql_reset_thd_for_next_command(thd);
@@ -2395,6 +2404,7 @@ void mysql_stmt_reset(THD *thd, char *pa
   ulong stmt_id= uint4korr(packet);
   Prepared_statement *stmt;
   DBUG_ENTER("mysql_stmt_reset");
+  DBUG_PRINT("enter", ("stmt_id=[%lu]", stmt_id));
 
   /* First of all clear possible warnings from the previous command */
   mysql_reset_thd_for_next_command(thd);
@@ -2430,6 +2440,7 @@ void mysql_stmt_close(THD *thd, char *pa
   ulong stmt_id= uint4korr(packet);
   Prepared_statement *stmt;
   DBUG_ENTER("mysql_stmt_close");
+  DBUG_PRINT("enter", ("stmt_id=[%lu]", stmt_id));
 
   if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close")))
     DBUG_VOID_RETURN;
@@ -2512,6 +2523,7 @@ void mysql_stmt_get_longdata(THD *thd, c
 #endif
 
   stmt_id= uint4korr(packet);
+  DBUG_PRINT("enter", ("stmt_id=[%lu]", stmt_id));
   packet+= 4;
 
   if (!(stmt=find_prepared_statement(thd, stmt_id,
@@ -2732,6 +2744,7 @@ bool Prepared_statement::prepare(const c
   Statement stmt_backup;
   Query_arena *old_stmt_arena;
   DBUG_ENTER("Prepared_statement::prepare");
+  DBUG_PRINT("enter", ("stmt=0x%lx", this));
   /*
     If this is an SQLCOM_PREPARE, we also increase Com_prepare_sql.
     However, it seems handy if com_stmt_prepare is increased always,
@@ -2837,6 +2850,8 @@ bool Prepared_statement::execute(String 
   Query_arena *old_stmt_arena;
   Item *old_free_list;
   bool error= TRUE;
+  DBUG_ENTER("Prepared_statement::execute");
+  DBUG_PRINT("enter", ("stmt=0x%lx", this));
 
   statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status);
 
@@ -2844,12 +2859,12 @@ bool Prepared_statement::execute(String 
   if (state == Query_arena::ERROR)
   {
     my_message(last_errno, last_error, MYF(0));
-    return TRUE;
+    DBUG_RETURN(true);
   }
   if (flags & (uint) IS_IN_USE)
   {
     my_error(ER_PS_NO_RECURSION, MYF(0));
-    return TRUE;
+    DBUG_RETURN(true);
   }
 
   /*
@@ -2866,7 +2881,7 @@ bool Prepared_statement::execute(String 
   {
     DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
     my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
-    return TRUE;
+    DBUG_RETURN(true);
   }
 
   /* In case the command has a call to SP which re-uses this statement name */
@@ -2931,7 +2946,7 @@ bool Prepared_statement::execute(String 
 
 error:
   flags&= ~ (uint) IS_IN_USE;
-  return error;
+  DBUG_RETURN(error);
 }
 
 
@@ -2939,14 +2954,16 @@ error:
 
 bool Prepared_statement::deallocate()
 {
+  DBUG_ENTER("Prepared_statement::deallocate");
+  DBUG_PRINT("enter", ("stmt=0x%lx", this));
   /* We account deallocate in the same manner as mysql_stmt_close */
   statistic_increment(thd->status_var.com_stmt_close, &LOCK_status);
   if (flags & (uint) IS_IN_USE)
   {
     my_error(ER_PS_NO_RECURSION, MYF(0));
-    return TRUE;
+    DBUG_RETURN(true);
   }
   /* Statement map calls delete stmt on erase */
   thd->stmt_map.erase(this);
-  return FALSE;
+  DBUG_RETURN(false);
 }
Thread
bk commit into 5.1 tree (andrey:1.2213) BUG#16394ahristov26 Mar