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/22 15:48:02 andrey@lmy004. +15 -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)
BitKeeper/etc/ignore
1.231 06/03/22 15:47:49 andrey@lmy004. +1 -0
Added dbug/user.pdf to the ignore list
sql/sql_yacc.yy
1.472 06/03/22 15:47:48 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/22 15:47:48 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/22 15:47:48 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/22 15:47:48 andrey@lmy004. +2 -1
- print time (with microseconds) in the trace log.
sql/sql_lex.h
1.218 06/03/22 15:47:48 andrey@lmy004. +8 -0
- new variable to st_lex
sql/sql_lex.cc
1.172 06/03/22 15:47:48 andrey@lmy004. +1 -0
- add a member variable to help in cases where SUBSELECT is inappropriate
sql/sql_base.cc
1.310 06/03/22 15:47:48 andrey@lmy004. +1 -0
- trace log message
sql/sp_head.cc
1.211 06/03/22 15:47:48 andrey@lmy004. +3 -2
- move the code before the comment, where it's more appropriate
sql/event_timed.cc
1.46 06/03/22 15:47:48 andrey@lmy004. +113 -28
- late parsing of the AT/EVERY/STARTS/ENDS to support SUBqueries
sql/event_executor.cc
1.42 06/03/22 15:47:48 andrey@lmy004. +35 -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/22 15:47:48 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/22 15:47:48 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/22 15:47:47 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/22 15:47:47 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-22 15:47:48 +01: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-22 15:47:48 +01: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-22 15:47:48 +01: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-22 15:47:48 +01:00
@@ -3780,7 +3780,7 @@ end_with_restore_list:
res= -1;
break;
}
-
+ DBUG_PUSH("d:t:T");
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
res= evex_create_event(thd, lex->et, (uint) lex->create_info.options,
@@ -3793,6 +3793,7 @@ end_with_restore_list:
res= evex_drop_event(thd, lex->et, lex->drop_if_exists, &rows_affected);
default:;
}
+ DBUG_POP();
DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
res, rows_affected));
if (!res)
--- 1.315/sql/sql_show.cc 2006-02-28 18:33:25 +01:00
+++ 1.316/sql/sql_show.cc 2006-03-22 15:47:48 +01: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-22 15:47:48 +01: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-22 15:47:47 +01: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-22 15:47:47 +01: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-22 15:47:48 +01: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-22 15:47:48 +01: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-22 15:47:48 +01: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,8 +415,10 @@ 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_PUSH("d:t:T");
DBUG_PRINT("event_executor_main", ("EVEX thread started"));
@@ -464,7 +474,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 +504,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 +567,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 +609,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;
@@ -661,6 +680,7 @@ err_no_thd:
my_thread_end();
pthread_exit(0);
#endif
+ DBUG_POP();
DBUG_RETURN(0); // Can't return anything here
}
@@ -682,6 +702,7 @@ event_executor_worker(void *event_void)
MEM_ROOT worker_mem_root;
DBUG_ENTER("event_executor_worker");
+ DBUG_PUSH("d:t:T");
init_alloc_root(&worker_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
@@ -770,6 +791,7 @@ err_no_thd:
my_thread_end();
pthread_exit(0);
#endif
+ DBUG_POP();
DBUG_RETURN(0); // Can't return anything here
}
@@ -862,7 +884,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 +926,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 +1006,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-22 15:47:48 +01: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(<ime, TIME_NO_ZERO_DATE)))
- DBUG_RETURN(ER_WRONG_VALUE);
+ DBUG_RETURN(EVEX_BAD_PARAMS);
if (TIME_to_ulonglong_datetime(<ime) <
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(<ime, 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(<ime)));
- if (TIME_to_ulonglong_datetime(<ime) <
- TIME_to_ulonglong_datetime(&time_tmp))
- DBUG_RETURN(EVEX_BAD_PARAMS);
+ my_tz_UTC->gmt_sec_to_TIME(<ime_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(<ime, TIME_to_timestamp(thd, <ime, ¬_used));
+ DBUG_PRINT("info",("NOW =%lld", TIME_to_ulonglong_datetime(<ime_now)));
+ DBUG_PRINT("info",("STARTS=%lld", TIME_to_ulonglong_datetime(<ime)));
+ if (TIME_to_ulonglong_datetime(<ime) <
+ TIME_to_ulonglong_datetime(<ime_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(<ime, 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(<ime)));
- /*
- 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(<ime, TIME_to_timestamp(thd, <ime, ¬_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(<ime)));
+
DBUG_PRINT("info", ("ENDS after STARTS?"));
- if (!starts_null && my_time_compare(&starts, <ime) != -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, <ime) == 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(<ime_now, (my_time_t) thd->query_start());
DBUG_PRINT("info", ("ENDS after NOW?"));
- my_tz_UTC->gmt_sec_to_TIME(<ime_now, thd->query_start());
+ DBUG_PRINT("info", ("NOW =%lld", TIME_to_ulonglong_datetime(<ime_now)));
if (my_time_compare(<ime_now, <ime) == 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-22 15:47:48 +01: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.230/BitKeeper/etc/ignore 2006-02-28 22:07:01 +01:00
+++ 1.231/BitKeeper/etc/ignore 2006-03-22 15:47:49 +01:00
@@ -1617,3 +1617,4 @@ zlib/*.vcproj
libmysqld/partition_info.cc
storage/ndb/src/common/util/testBitmask.cpp
include/openssl
+dbug/user.pdf
--- 1.164/sql/sql_prepare.cc 2006-02-25 19:35:09 +01:00
+++ 1.165/sql/sql_prepare.cc 2006-03-22 15:47:48 +01: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#16394 | ahristov | 22 Mar |