2005-12-08 00:17:05 +01:00
|
|
|
/* Copyright (C) 2004-2005 MySQL AB
|
2005-12-05 11:45:04 +01:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
|
|
|
#include "event_priv.h"
|
2005-12-12 21:19:19 +01:00
|
|
|
#include "event.h"
|
2005-12-02 13:22:15 +01:00
|
|
|
#include "sp.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
TODO list :
|
2005-12-06 16:15:29 +01:00
|
|
|
- The default value of created/modified should not be 0000-00-00 because of
|
|
|
|
STRICT mode restricions.
|
2005-12-05 11:45:04 +01:00
|
|
|
|
|
|
|
- CREATE EVENT should not go into binary log! Does it now? The SQL statements
|
|
|
|
issued by the EVENT are replicated.
|
2005-12-07 19:26:44 +01:00
|
|
|
I have an idea how to solve the problem at failover. So the status field
|
|
|
|
will be ENUM('DISABLED', 'ENABLED', 'SLAVESIDE_DISABLED').
|
|
|
|
In this case when CREATE EVENT is replicated it should go into the binary
|
|
|
|
as SLAVESIDE_DISABLED if it is ENABLED, when it's created as DISABLEd it
|
|
|
|
should be replicated as disabled. If an event is ALTERed as DISABLED the
|
|
|
|
query should go untouched into the binary log, when ALTERed as enable then
|
|
|
|
it should go as SLAVESIDE_DISABLED. This is regarding the SQL interface.
|
|
|
|
TT routines however modify mysql.event internally and this does not go the log
|
|
|
|
so in this case queries has to be injected into the log...somehow... or
|
|
|
|
maybe a solution is RBR for this case, because the event may go only from
|
|
|
|
ENABLED to DISABLED status change and this is safe for replicating. As well
|
|
|
|
an event may be deleted which is also safe for RBR.
|
2005-12-05 11:45:04 +01:00
|
|
|
|
|
|
|
- Maybe move all allocations during parsing to evex_mem_root thus saving
|
2005-12-02 13:22:15 +01:00
|
|
|
double parsing in evex_create_event!
|
2005-12-05 11:45:04 +01:00
|
|
|
|
2005-12-13 19:16:00 +01:00
|
|
|
- If the server is killed (stopping) try to kill executing events?
|
2005-12-05 11:45:04 +01:00
|
|
|
|
|
|
|
- What happens if one renames an event in the DB while it is in memory?
|
2005-12-07 22:29:00 +01:00
|
|
|
Or even deleting it?
|
|
|
|
|
2005-12-05 11:45:04 +01:00
|
|
|
- Consider using conditional variable when doing shutdown instead of
|
2005-12-13 19:16:00 +01:00
|
|
|
waiting till all worker threads end.
|
|
|
|
|
2005-12-05 11:45:04 +01:00
|
|
|
- Make event_timed::get_show_create_event() work
|
2005-12-12 21:19:19 +01:00
|
|
|
|
2005-12-05 11:45:04 +01:00
|
|
|
- Add function documentation whenever needed.
|
2005-12-12 21:19:19 +01:00
|
|
|
|
2005-12-05 11:45:04 +01:00
|
|
|
- Add logging to file
|
|
|
|
|
2005-12-12 21:19:19 +01:00
|
|
|
- Move comparison code to class event_timed
|
|
|
|
|
2005-12-05 11:45:04 +01:00
|
|
|
Warning:
|
|
|
|
- For now parallel execution is not possible because the same sp_head cannot be
|
|
|
|
executed few times!!! There is still no lock attached to particular event.
|
|
|
|
|
2005-12-07 22:29:00 +01:00
|
|
|
*/
|
2005-12-05 11:45:04 +01:00
|
|
|
|
|
|
|
|
2005-12-13 13:21:11 +01:00
|
|
|
QUEUE EVEX_EQ_NAME;
|
2005-12-05 11:45:04 +01:00
|
|
|
MEM_ROOT evex_mem_root;
|
|
|
|
|
|
|
|
|
2005-12-12 21:19:19 +01:00
|
|
|
void
|
|
|
|
evex_queue_init(EVEX_QUEUE_TYPE *queue)
|
|
|
|
{
|
|
|
|
if (init_queue_ex(queue, 100 /*num_el*/, 0 /*offset*/,
|
|
|
|
0 /*smallest_on_top*/, event_timed_compare_q, NULL,
|
|
|
|
100 /*auto_extent*/))
|
|
|
|
sql_print_error("Insufficient memory to initialize executing queue.");
|
|
|
|
}
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
|
2005-12-08 20:37:54 +01:00
|
|
|
static
|
|
|
|
int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
|
|
|
|
{
|
|
|
|
return cs->coll->strnncollsp(cs,
|
|
|
|
(unsigned char *) s.str,s.length,
|
|
|
|
(unsigned char *) t.str,t.length, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-12 21:19:19 +01:00
|
|
|
int
|
2005-12-02 13:22:15 +01:00
|
|
|
my_time_compare(TIME *a, TIME *b)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Or maybe it is faster to use TIME_to_ulonglong_datetime
|
|
|
|
for "a" and "b"
|
|
|
|
*/
|
|
|
|
|
|
|
|
DBUG_ENTER("my_time_compare");
|
2005-12-12 21:19:19 +01:00
|
|
|
|
2005-12-02 13:22:15 +01:00
|
|
|
if (a->year > b->year)
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
|
|
|
if (a->year < b->year)
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
|
|
|
|
if (a->month > b->month)
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
|
|
|
if (a->month < b->month)
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
|
|
|
|
if (a->day > b->day)
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
|
|
|
if (a->day < b->day)
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
|
|
|
|
if (a->hour > b->hour)
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
|
|
|
if (a->hour < b->hour)
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
|
|
|
|
if (a->minute > b->minute)
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
|
|
|
if (a->minute < b->minute)
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
|
|
|
|
if (a->second > b->second)
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
|
|
|
if (a->second < b->second)
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
|
2005-12-12 21:19:19 +01:00
|
|
|
|
|
|
|
if (a->second_part > b->second_part)
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
|
|
|
if (a->second_part < b->second_part)
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
2005-12-13 13:21:11 +01:00
|
|
|
|
2005-12-12 21:19:19 +01:00
|
|
|
int
|
|
|
|
evex_time_diff(TIME *a, TIME *b)
|
|
|
|
{
|
|
|
|
my_bool in_gap;
|
|
|
|
DBUG_ENTER("my_time_diff");
|
|
|
|
|
|
|
|
return sec_since_epoch_TIME(a) - sec_since_epoch_TIME(b);
|
|
|
|
}
|
|
|
|
|
2005-12-02 13:22:15 +01:00
|
|
|
|
2005-12-05 11:45:04 +01:00
|
|
|
inline int
|
2005-12-02 13:22:15 +01:00
|
|
|
event_timed_compare(event_timed **a, event_timed **b)
|
|
|
|
{
|
2005-12-12 21:19:19 +01:00
|
|
|
my_ulonglong a_t, b_t;
|
|
|
|
a_t= TIME_to_ulonglong_datetime(&(*a)->execute_at)*100L +
|
|
|
|
(*a)->execute_at.second_part;
|
|
|
|
b_t= TIME_to_ulonglong_datetime(&(*b)->execute_at)*100L +
|
|
|
|
(*b)->execute_at.second_part;
|
|
|
|
|
|
|
|
if (a_t > b_t)
|
|
|
|
return 1;
|
|
|
|
else if (a_t < b_t)
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-12 21:19:19 +01:00
|
|
|
int
|
|
|
|
event_timed_compare_q(void *vptr, byte* a, byte *b)
|
|
|
|
{
|
|
|
|
return event_timed_compare((event_timed **)&a, (event_timed **)&b);
|
|
|
|
}
|
|
|
|
|
2005-12-06 16:15:29 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Open mysql.event table for read
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
evex_open_event_table_for_read()
|
|
|
|
thd Thread context
|
|
|
|
lock_type How to lock the table
|
2005-12-16 12:42:39 +01:00
|
|
|
table The table pointer
|
2005-12-06 16:15:29 +01:00
|
|
|
RETURN
|
2005-12-16 12:42:39 +01:00
|
|
|
1 Cannot lock table
|
|
|
|
2 The table is corrupted - different number of fields
|
|
|
|
0 OK
|
2005-12-06 16:15:29 +01:00
|
|
|
*/
|
|
|
|
|
2005-12-16 12:42:39 +01:00
|
|
|
int
|
|
|
|
evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table)
|
2005-12-06 16:15:29 +01:00
|
|
|
{
|
|
|
|
TABLE_LIST tables;
|
|
|
|
bool not_used;
|
|
|
|
DBUG_ENTER("open_proc_table");
|
|
|
|
|
|
|
|
bzero((char*) &tables, sizeof(tables));
|
|
|
|
tables.db= (char*) "mysql";
|
|
|
|
tables.table_name= tables.alias= (char*) "event";
|
|
|
|
tables.lock_type= lock_type;
|
|
|
|
|
|
|
|
if (simple_open_n_lock_tables(thd, &tables))
|
2005-12-16 12:42:39 +01:00
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
|
|
|
if (tables.table->s->fields != EVEX_FIELD_COUNT)
|
|
|
|
{
|
|
|
|
my_error(ER_EVENT_COL_COUNT_DOESNT_MATCH, MYF(0), "mysql", "event");
|
|
|
|
close_thread_tables(thd);
|
|
|
|
DBUG_RETURN(2);
|
|
|
|
}
|
|
|
|
*table= tables.table;
|
2005-12-06 16:15:29 +01:00
|
|
|
|
2005-12-16 12:42:39 +01:00
|
|
|
DBUG_RETURN(0);
|
2005-12-06 16:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Find row in open mysql.event table representing event
|
|
|
|
|
|
|
|
SYNOPSIS
|
2005-12-08 15:34:11 +01:00
|
|
|
evex_db_find_event_aux()
|
2005-12-06 16:15:29 +01:00
|
|
|
thd Thread context
|
|
|
|
dbname Name of event's database
|
|
|
|
rname Name of the event inside the db
|
|
|
|
table TABLE object for open mysql.event table.
|
|
|
|
|
|
|
|
RETURN VALUE
|
2005-12-08 15:34:11 +01:00
|
|
|
0 - Routine found
|
|
|
|
EVEX_KEY_NOT_FOUND - No routine with given name
|
2005-12-06 16:15:29 +01:00
|
|
|
*/
|
|
|
|
|
2005-12-06 16:46:29 +01:00
|
|
|
int
|
2005-12-08 15:34:11 +01:00
|
|
|
evex_db_find_event_aux(THD *thd, const LEX_STRING dbname,
|
2005-12-07 22:29:00 +01:00
|
|
|
const LEX_STRING ev_name, TABLE *table)
|
2005-12-06 16:15:29 +01:00
|
|
|
{
|
2005-12-08 15:34:11 +01:00
|
|
|
byte key[MAX_KEY_LENGTH];
|
|
|
|
DBUG_ENTER("evex_db_find_event_aux");
|
2005-12-07 22:29:00 +01:00
|
|
|
DBUG_PRINT("enter", ("name: %.*s", ev_name.length, ev_name.str));
|
2005-12-06 16:15:29 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Create key to find row. We have to use field->store() to be able to
|
|
|
|
handle VARCHAR and CHAR fields.
|
|
|
|
Assumption here is that the two first fields in the table are
|
|
|
|
'db' and 'name' and the first key is the primary key over the
|
|
|
|
same fields.
|
|
|
|
*/
|
2005-12-08 15:34:11 +01:00
|
|
|
if (dbname.length > table->field[EVEX_FIELD_DB]->field_length ||
|
|
|
|
ev_name.length > table->field[EVEX_FIELD_NAME]->field_length)
|
2005-12-07 22:29:00 +01:00
|
|
|
DBUG_RETURN(EVEX_KEY_NOT_FOUND);
|
2005-12-07 19:26:44 +01:00
|
|
|
|
2005-12-06 16:15:29 +01:00
|
|
|
table->field[0]->store(dbname.str, dbname.length, &my_charset_bin);
|
2005-12-07 22:29:00 +01:00
|
|
|
table->field[1]->store(ev_name.str, ev_name.length, &my_charset_bin);
|
2005-12-06 16:15:29 +01:00
|
|
|
key_copy(key, table->record[0], table->key_info, table->key_info->key_length);
|
|
|
|
|
2005-12-07 19:26:44 +01:00
|
|
|
if (table->file->index_read_idx(table->record[0], 0, key,
|
2005-12-07 22:29:00 +01:00
|
|
|
table->key_info->key_length,HA_READ_KEY_EXACT))
|
|
|
|
DBUG_RETURN(EVEX_KEY_NOT_FOUND);
|
2005-12-06 16:15:29 +01:00
|
|
|
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-12-02 13:22:15 +01:00
|
|
|
/*
|
|
|
|
Puts some data common to CREATE and ALTER EVENT into a row.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
evex_fill_row()
|
|
|
|
thd THD
|
|
|
|
table the row to fill out
|
|
|
|
et Event's data
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Used both when an event is created and when it is altered.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
2005-12-06 16:15:29 +01:00
|
|
|
evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
|
|
|
DBUG_ENTER("evex_fill_row");
|
|
|
|
|
|
|
|
if (table->s->fields != EVEX_FIELD_COUNT)
|
2005-12-07 19:26:44 +01:00
|
|
|
{
|
|
|
|
my_error(ER_EVENT_COL_COUNT_DOESNT_MATCH, MYF(0), "mysql", "event");
|
2005-12-06 16:15:29 +01:00
|
|
|
DBUG_RETURN(EVEX_GET_FIELD_FAILED);
|
2005-12-07 19:26:44 +01:00
|
|
|
}
|
|
|
|
|
2005-12-08 00:17:05 +01:00
|
|
|
DBUG_PRINT("info", ("dbname.len=%d",et->dbname.length));
|
|
|
|
DBUG_PRINT("info", ("name.len=%d",et->name.length));
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
table->field[EVEX_FIELD_DB]->
|
2005-12-08 00:17:05 +01:00
|
|
|
store(et->dbname.str, et->dbname.length, system_charset_info);
|
2005-12-02 13:22:15 +01:00
|
|
|
table->field[EVEX_FIELD_NAME]->
|
2005-12-08 00:17:05 +01:00
|
|
|
store(et->name.str, et->name.length, system_charset_info);
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
table->field[EVEX_FIELD_ON_COMPLETION]->set_notnull();
|
2005-12-08 00:17:05 +01:00
|
|
|
table->field[EVEX_FIELD_ON_COMPLETION]->store((longlong)et->on_completion);
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
table->field[EVEX_FIELD_STATUS]->set_notnull();
|
2005-12-08 00:17:05 +01:00
|
|
|
table->field[EVEX_FIELD_STATUS]->store((longlong)et->status);
|
|
|
|
// et->status_changed= false;
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
// ToDo: Andrey. How to use users current charset?
|
2005-12-08 00:17:05 +01:00
|
|
|
if (et->body.str)
|
2005-12-02 13:22:15 +01:00
|
|
|
table->field[EVEX_FIELD_BODY]->
|
2005-12-08 00:17:05 +01:00
|
|
|
store(et->body.str, et->body.length, system_charset_info);
|
2005-12-02 13:22:15 +01:00
|
|
|
|
2005-12-08 00:17:05 +01:00
|
|
|
if (et->starts.year)
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
|
|
|
table->field[EVEX_FIELD_STARTS]->set_notnull();// set NULL flag to OFF
|
2005-12-08 00:17:05 +01:00
|
|
|
table->field[EVEX_FIELD_STARTS]->store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
|
|
|
|
2005-12-08 00:17:05 +01:00
|
|
|
if (et->ends.year)
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
|
|
|
table->field[EVEX_FIELD_ENDS]->set_notnull();
|
2005-12-08 00:17:05 +01:00
|
|
|
table->field[EVEX_FIELD_ENDS]->store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
|
|
|
|
2005-12-08 00:17:05 +01:00
|
|
|
if (et->expression)
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
|
|
|
table->field[EVEX_FIELD_INTERVAL_EXPR]->set_notnull();
|
2005-12-08 00:17:05 +01:00
|
|
|
table->field[EVEX_FIELD_INTERVAL_EXPR]->store((longlong)et->expression);
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_notnull();
|
2005-12-05 11:45:04 +01:00
|
|
|
/*
|
|
|
|
In the enum (C) intervals start from 0 but in mysql enum valid values start
|
|
|
|
from 1. Thus +1 offset is needed!
|
|
|
|
*/
|
2005-12-08 00:17:05 +01:00
|
|
|
table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval + 1);
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
2005-12-08 00:17:05 +01:00
|
|
|
else if (et->execute_at.year)
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
|
|
|
// fix_fields already called in init_execute_at
|
|
|
|
table->field[EVEX_FIELD_EXECUTE_AT]->set_notnull();
|
2005-12-08 00:17:05 +01:00
|
|
|
table->field[EVEX_FIELD_EXECUTE_AT]->store_time(&et->execute_at,
|
2005-12-06 16:15:29 +01:00
|
|
|
MYSQL_TIMESTAMP_DATETIME);
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
//this will make it NULL because we don't call set_notnull
|
|
|
|
table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->store((longlong) 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-12-06 16:15:29 +01:00
|
|
|
DBUG_ASSERT(is_update);
|
2005-12-02 13:22:15 +01:00
|
|
|
// it is normal to be here when the action is update
|
|
|
|
// this is an error if the action is create. something is borked
|
|
|
|
}
|
|
|
|
|
|
|
|
((Field_timestamp *)table->field[EVEX_FIELD_MODIFIED])->set_time();
|
|
|
|
|
2005-12-08 00:17:05 +01:00
|
|
|
if (et->comment.length)
|
2005-12-02 13:22:15 +01:00
|
|
|
table->field[EVEX_FIELD_COMMENT]->
|
2005-12-08 00:17:05 +01:00
|
|
|
store(et->comment.str, et->comment.length, system_charset_info);
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Creates an event in mysql.event
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
db_create_event()
|
|
|
|
thd THD
|
|
|
|
et event_timed object containing information for the event
|
|
|
|
|
2005-12-08 15:34:11 +01:00
|
|
|
Return value
|
|
|
|
0 - OK
|
|
|
|
EVEX_GENERAL_ERROR - Failure
|
2005-12-02 13:22:15 +01:00
|
|
|
DESCRIPTION
|
|
|
|
Creates an event. Relies on evex_fill_row which is shared with
|
|
|
|
db_update_event. The name of the event is inside "et".
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
|
|
|
db_create_event(THD *thd, event_timed *et)
|
|
|
|
{
|
2005-12-06 16:15:29 +01:00
|
|
|
int ret= EVEX_OK;
|
2005-12-02 13:22:15 +01:00
|
|
|
TABLE *table;
|
|
|
|
char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
|
|
|
|
char olddb[128];
|
2005-12-06 16:15:29 +01:00
|
|
|
bool dbchanged= false;
|
2005-12-02 13:22:15 +01:00
|
|
|
DBUG_ENTER("db_create_event");
|
2005-12-08 00:17:05 +01:00
|
|
|
DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
|
2005-12-02 13:22:15 +01:00
|
|
|
|
2005-12-06 16:15:29 +01:00
|
|
|
|
|
|
|
DBUG_PRINT("info", ("open mysql.event for update"));
|
2005-12-16 12:42:39 +01:00
|
|
|
if (evex_open_event_table(thd, TL_WRITE, &table))
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
2005-12-06 16:15:29 +01:00
|
|
|
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
2005-12-07 19:26:44 +01:00
|
|
|
goto err;
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
|
|
|
|
2005-12-06 16:15:29 +01:00
|
|
|
DBUG_PRINT("info", ("check existance of an event with the same name"));
|
2005-12-08 15:34:11 +01:00
|
|
|
if (!evex_db_find_event_aux(thd, et->dbname, et->name, table))
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
2005-12-08 00:17:05 +01:00
|
|
|
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), et->name.str);
|
2005-12-07 19:26:44 +01:00
|
|
|
goto err;
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
|
|
|
|
2005-12-06 16:15:29 +01:00
|
|
|
DBUG_PRINT("info", ("non-existant, go forward"));
|
2005-12-08 00:17:05 +01:00
|
|
|
if ((ret= sp_use_new_db(thd, et->dbname.str,olddb, sizeof(olddb),0, &dbchanged)))
|
2005-12-06 16:15:29 +01:00
|
|
|
{
|
|
|
|
my_error(ER_BAD_DB_ERROR, MYF(0));
|
2005-12-07 19:26:44 +01:00
|
|
|
goto err;
|
2005-12-06 16:15:29 +01:00
|
|
|
}
|
|
|
|
|
2005-12-02 13:22:15 +01:00
|
|
|
restore_record(table, s->default_values); // Get default values for fields
|
|
|
|
|
2005-12-08 00:17:05 +01:00
|
|
|
if (et->name.length > table->field[EVEX_FIELD_NAME]->field_length)
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
2005-12-08 00:17:05 +01:00
|
|
|
my_error(ER_TOO_LONG_IDENT, MYF(0), et->name.str);
|
2005-12-07 22:29:00 +01:00
|
|
|
goto err;
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
2005-12-08 00:17:05 +01:00
|
|
|
if (et->body.length > table->field[EVEX_FIELD_BODY]->field_length)
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
2005-12-08 00:17:05 +01:00
|
|
|
my_error(ER_TOO_LONG_BODY, MYF(0), et->name.str);
|
2005-12-07 22:29:00 +01:00
|
|
|
goto err;
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
2005-12-07 22:29:00 +01:00
|
|
|
|
2005-12-08 00:17:05 +01:00
|
|
|
if (!(et->expression) && !(et->execute_at.year))
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
2005-12-08 00:17:05 +01:00
|
|
|
DBUG_PRINT("error", ("neither expression nor execute_at are set!"));
|
2005-12-08 15:34:11 +01:00
|
|
|
my_error(ER_EVENT_NEITHER_M_EXPR_NOR_M_AT, MYF(0));
|
2005-12-07 19:26:44 +01:00
|
|
|
goto err;
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
2005-12-06 16:15:29 +01:00
|
|
|
|
2005-12-08 00:17:05 +01:00
|
|
|
strxmov(definer, et->definer_user.str, "@", et->definer_host.str, NullS);
|
2005-12-08 15:34:11 +01:00
|
|
|
if ((ret=table->field[EVEX_FIELD_DEFINER]->
|
2005-12-08 00:17:05 +01:00
|
|
|
store(definer, et->definer_user.length + 1 + et->definer_host.length,
|
2005-12-08 15:34:11 +01:00
|
|
|
system_charset_info)))
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
2005-12-08 15:34:11 +01:00
|
|
|
my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
|
2005-12-07 19:26:44 +01:00
|
|
|
goto err;
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
2005-12-06 16:15:29 +01:00
|
|
|
|
2005-12-02 13:22:15 +01:00
|
|
|
((Field_timestamp *)table->field[EVEX_FIELD_CREATED])->set_time();
|
2005-12-08 15:34:11 +01:00
|
|
|
|
|
|
|
// evex_fill_row() calls my_error() in case of error so no need to handle it here
|
2005-12-06 16:15:29 +01:00
|
|
|
if ((ret= evex_fill_row(thd, table, et, false)))
|
2005-12-07 19:26:44 +01:00
|
|
|
goto err;
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
if (table->file->write_row(table->record[0]))
|
2005-12-07 19:26:44 +01:00
|
|
|
{
|
2005-12-08 15:34:11 +01:00
|
|
|
my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
|
2005-12-07 19:26:44 +01:00
|
|
|
goto err;
|
|
|
|
}
|
2005-12-07 22:29:00 +01:00
|
|
|
|
|
|
|
if (mysql_bin_log.is_open())
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
|
|
|
thd->clear_error();
|
|
|
|
/* Such a statement can always go directly to binlog, no trans cache */
|
|
|
|
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
|
|
|
mysql_bin_log.write(&qinfo);
|
|
|
|
}
|
|
|
|
|
2005-12-07 19:26:44 +01:00
|
|
|
if (dbchanged)
|
|
|
|
(void) mysql_change_db(thd, olddb, 1);
|
2005-12-13 13:21:11 +01:00
|
|
|
if (table)
|
|
|
|
close_thread_tables(thd);
|
2005-12-07 19:26:44 +01:00
|
|
|
DBUG_RETURN(EVEX_OK);
|
2005-12-06 16:15:29 +01:00
|
|
|
|
2005-12-07 19:26:44 +01:00
|
|
|
err:
|
2005-12-02 13:22:15 +01:00
|
|
|
if (dbchanged)
|
2005-12-06 16:15:29 +01:00
|
|
|
(void) mysql_change_db(thd, olddb, 1);
|
2005-12-13 13:21:11 +01:00
|
|
|
if (table)
|
|
|
|
close_thread_tables(thd);
|
2005-12-07 19:26:44 +01:00
|
|
|
DBUG_RETURN(EVEX_GENERAL_ERROR);
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2005-12-08 15:34:11 +01:00
|
|
|
Used to execute ALTER EVENT. Pendant to evex_update_event().
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
db_update_event()
|
|
|
|
thd THD
|
|
|
|
sp_name the name of the event to alter
|
|
|
|
et event's data
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
sp_name is passed since this is the name of the event to
|
|
|
|
alter in case of RENAME TO.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
2005-12-08 15:34:11 +01:00
|
|
|
db_update_event(THD *thd, event_timed *et, sp_name *new_name)
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
|
|
|
TABLE *table;
|
2005-12-07 22:29:00 +01:00
|
|
|
int ret= EVEX_OPEN_TABLE_FAILED;
|
2005-12-02 13:22:15 +01:00
|
|
|
DBUG_ENTER("db_update_event");
|
2005-12-08 00:17:05 +01:00
|
|
|
DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
|
|
|
|
if (new_name)
|
|
|
|
DBUG_PRINT("enter", ("rename to: %.*s", new_name->m_name.length,
|
|
|
|
new_name->m_name.str));
|
2005-12-02 13:22:15 +01:00
|
|
|
|
2005-12-16 12:42:39 +01:00
|
|
|
if (evex_open_event_table(thd, TL_WRITE, &table))
|
2005-12-06 16:15:29 +01:00
|
|
|
{
|
|
|
|
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
2005-12-07 19:26:44 +01:00
|
|
|
goto err;
|
2005-12-06 16:15:29 +01:00
|
|
|
}
|
2005-12-08 15:34:11 +01:00
|
|
|
|
|
|
|
// first look whether we overwrite
|
2005-12-08 20:37:54 +01:00
|
|
|
if (new_name)
|
2005-12-08 15:34:11 +01:00
|
|
|
{
|
2005-12-08 20:37:54 +01:00
|
|
|
if (!sortcmp_lex_string(et->name, new_name->m_name, system_charset_info) &&
|
|
|
|
!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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!evex_db_find_event_aux(thd, new_name->m_db, new_name->m_name, table))
|
|
|
|
{
|
|
|
|
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str);
|
|
|
|
goto err;
|
|
|
|
}
|
2005-12-08 15:34:11 +01:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
...and then whether there is such an event. don't exchange the blocks
|
|
|
|
because you will get error 120 from table handler because new_name will
|
|
|
|
overwrite the key and SE will tell us that it cannot find the already found
|
|
|
|
row (copied into record[1] later
|
|
|
|
*/
|
|
|
|
if (EVEX_KEY_NOT_FOUND == evex_db_find_event_aux(thd, et->dbname, et->name,
|
2005-12-07 22:29:00 +01:00
|
|
|
table))
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
2005-12-08 00:17:05 +01:00
|
|
|
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str);
|
2005-12-07 19:26:44 +01:00
|
|
|
goto err;
|
2005-12-06 16:15:29 +01:00
|
|
|
}
|
2005-12-08 15:34:11 +01:00
|
|
|
|
2005-12-06 16:15:29 +01:00
|
|
|
|
|
|
|
store_record(table,record[1]);
|
|
|
|
|
2005-12-07 19:26:44 +01:00
|
|
|
// Don't update create on row update.
|
|
|
|
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
|
|
|
|
|
|
|
|
// evex_fill_row() calls my_error() in case of error so no need to handle it here
|
2005-12-06 16:15:29 +01:00
|
|
|
if ((ret= evex_fill_row(thd, table, et, true)))
|
2005-12-07 19:26:44 +01:00
|
|
|
goto err;
|
2005-12-06 16:15:29 +01:00
|
|
|
|
2005-12-08 00:17:05 +01:00
|
|
|
if (new_name)
|
2005-12-06 16:15:29 +01:00
|
|
|
{
|
|
|
|
table->field[EVEX_FIELD_DB]->
|
2005-12-08 00:17:05 +01:00
|
|
|
store(new_name->m_db.str, new_name->m_db.length, system_charset_info);
|
2005-12-06 16:15:29 +01:00
|
|
|
table->field[EVEX_FIELD_NAME]->
|
2005-12-08 00:17:05 +01:00
|
|
|
store(new_name->m_name.str, new_name->m_name.length, system_charset_info);
|
2005-12-06 16:15:29 +01:00
|
|
|
}
|
2005-12-02 13:22:15 +01:00
|
|
|
|
2005-12-07 19:26:44 +01:00
|
|
|
if ((ret= table->file->update_row(table->record[1], table->record[0])))
|
2005-12-06 16:15:29 +01:00
|
|
|
{
|
2005-12-08 15:34:11 +01:00
|
|
|
my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
|
2005-12-07 19:26:44 +01:00
|
|
|
goto err;
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
2005-12-07 19:26:44 +01:00
|
|
|
|
|
|
|
// close mysql.event or we crash later when loading the event from disk
|
2005-12-02 13:22:15 +01:00
|
|
|
close_thread_tables(thd);
|
2005-12-07 19:26:44 +01:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (table)
|
|
|
|
close_thread_tables(thd);
|
|
|
|
DBUG_RETURN(EVEX_GENERAL_ERROR);
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
|
|
|
|
2005-12-06 16:15:29 +01:00
|
|
|
|
2005-12-02 13:22:15 +01:00
|
|
|
/*
|
2005-12-07 22:29:00 +01:00
|
|
|
Looks for a named event in mysql.event and in case of success returns
|
|
|
|
an object will data loaded from the table.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
db_find_event()
|
|
|
|
thd THD
|
|
|
|
name the name of the event to find
|
|
|
|
ett event's data if event is found
|
|
|
|
tbl TABLE object to use when not NULL
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
1) Use sp_name for look up, return in **ett if found
|
|
|
|
2) tbl is not closed at exit
|
2005-12-02 13:22:15 +01:00
|
|
|
*/
|
2005-12-07 22:29:00 +01:00
|
|
|
|
2005-12-02 13:22:15 +01:00
|
|
|
static int
|
2005-12-07 19:26:44 +01:00
|
|
|
db_find_event(THD *thd, sp_name *name, event_timed **ett, TABLE *tbl)
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
|
|
|
TABLE *table;
|
|
|
|
int ret;
|
|
|
|
const char *definer;
|
|
|
|
char *ptr;
|
|
|
|
event_timed *et;
|
|
|
|
DBUG_ENTER("db_find_event");
|
2005-12-07 19:26:44 +01:00
|
|
|
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
|
2005-12-02 13:22:15 +01:00
|
|
|
|
2005-12-07 19:26:44 +01:00
|
|
|
if (tbl)
|
|
|
|
table= tbl;
|
2005-12-16 12:42:39 +01:00
|
|
|
else if (evex_open_event_table(thd, TL_READ, &table))
|
2005-12-06 16:15:29 +01:00
|
|
|
{
|
|
|
|
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
2005-12-07 19:26:44 +01:00
|
|
|
ret= EVEX_GENERAL_ERROR;
|
2005-12-06 16:15:29 +01:00
|
|
|
goto done;
|
|
|
|
}
|
2005-12-02 13:22:15 +01:00
|
|
|
|
2005-12-08 15:34:11 +01:00
|
|
|
if ((ret= evex_db_find_event_aux(thd, name->m_db, name->m_name, table)))
|
2005-12-07 19:26:44 +01:00
|
|
|
{
|
2005-12-08 00:17:05 +01:00
|
|
|
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name->m_name.str);
|
2005-12-07 19:26:44 +01:00
|
|
|
goto done;
|
|
|
|
}
|
2005-12-02 13:22:15 +01:00
|
|
|
et= new event_timed;
|
|
|
|
|
|
|
|
/*
|
2005-12-07 19:26:44 +01:00
|
|
|
1)The table should not be closed beforehand. ::load_from_row() only loads
|
|
|
|
and does not compile
|
|
|
|
|
|
|
|
2)::load_from_row() is silent on error therefore we emit error msg here
|
2005-12-02 13:22:15 +01:00
|
|
|
*/
|
|
|
|
if ((ret= et->load_from_row(&evex_mem_root, table)))
|
2005-12-07 19:26:44 +01:00
|
|
|
{
|
|
|
|
my_error(ER_EVENT_CANNOT_LOAD_FROM_TABLE, MYF(0));
|
2005-12-02 13:22:15 +01:00
|
|
|
goto done;
|
2005-12-07 19:26:44 +01:00
|
|
|
}
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
done:
|
|
|
|
if (ret && et)
|
|
|
|
{
|
|
|
|
delete et;
|
|
|
|
et= 0;
|
|
|
|
}
|
2005-12-07 19:26:44 +01:00
|
|
|
// don't close the table if we haven't opened it ourselves
|
2005-12-13 23:10:29 +01:00
|
|
|
if (!tbl && table)
|
2005-12-07 19:26:44 +01:00
|
|
|
close_thread_tables(thd);
|
2005-12-02 13:22:15 +01:00
|
|
|
*ett= et;
|
|
|
|
DBUG_RETURN(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-07 22:29:00 +01:00
|
|
|
/*
|
|
|
|
Looks for a named event in mysql.event and then loads it from
|
|
|
|
the table, compiles it and insert it into the cache.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
evex_load_and_compile_event()
|
|
|
|
thd THD
|
|
|
|
spn the name of the event to alter
|
|
|
|
use_lock whether to obtain a lock on LOCK_event_arrays or not
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
0 - OK
|
|
|
|
< 0 - error (in this case underlying functions call my_error()).
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2005-12-02 13:22:15 +01:00
|
|
|
static int
|
|
|
|
evex_load_and_compile_event(THD * thd, sp_name *spn, bool use_lock)
|
|
|
|
{
|
|
|
|
int ret= 0;
|
|
|
|
MEM_ROOT *tmp_mem_root;
|
2005-12-13 19:16:00 +01:00
|
|
|
event_timed *ett;
|
2005-12-15 14:12:28 +01:00
|
|
|
Open_tables_state backup;
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
DBUG_ENTER("db_load_and_compile_event");
|
|
|
|
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;
|
|
|
|
|
2005-12-15 14:12:28 +01:00
|
|
|
thd->reset_n_backup_open_tables_state(&backup);
|
2005-12-07 19:26:44 +01:00
|
|
|
// no need to use my_error() here because db_find_event() has done it
|
|
|
|
if ((ret= db_find_event(thd, spn, &ett, NULL)))
|
2005-12-02 13:22:15 +01:00
|
|
|
goto done;
|
|
|
|
|
2005-12-15 14:12:28 +01:00
|
|
|
thd->restore_backup_open_tables_state(&backup);
|
2005-12-02 13:22:15 +01:00
|
|
|
/*
|
2005-12-07 19:26:44 +01:00
|
|
|
allocate on evex_mem_root. if you call without evex_mem_root
|
2005-12-08 00:17:05 +01:00
|
|
|
then sphead will not be cleared!
|
2005-12-02 13:22:15 +01:00
|
|
|
*/
|
|
|
|
if ((ret= ett->compile(thd, &evex_mem_root)))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
ett->compute_next_execution_time();
|
|
|
|
if (use_lock)
|
|
|
|
VOID(pthread_mutex_lock(&LOCK_event_arrays));
|
|
|
|
|
2005-12-13 19:16:00 +01:00
|
|
|
evex_queue_insert(&EVEX_EQ_NAME, (EVEX_PTOQEL) ett);
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
/*
|
2005-12-08 00:17:05 +01:00
|
|
|
There is a copy in the array which we don't need. sphead won't be
|
2005-12-02 13:22:15 +01:00
|
|
|
destroyed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (use_lock)
|
|
|
|
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (thd->mem_root != tmp_mem_root)
|
|
|
|
thd->mem_root= tmp_mem_root;
|
|
|
|
|
|
|
|
DBUG_RETURN(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock)
|
|
|
|
{
|
|
|
|
uint i;
|
|
|
|
|
|
|
|
DBUG_ENTER("evex_remove_from_cache");
|
|
|
|
/*
|
|
|
|
It is possible that 2 (or 1) pass(es) won't find the event in memory.
|
|
|
|
The reason is that DISABLED events are not cached.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (use_lock)
|
|
|
|
VOID(pthread_mutex_lock(&LOCK_event_arrays));
|
2005-12-13 13:21:11 +01:00
|
|
|
|
2005-12-12 21:19:19 +01:00
|
|
|
for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i)
|
|
|
|
{
|
2005-12-13 13:21:11 +01:00
|
|
|
event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, event_timed*);
|
2005-12-12 21:19:19 +01:00
|
|
|
DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?",db->str,name->str, et->dbname.str,
|
|
|
|
et->name.str));
|
|
|
|
if (!sortcmp_lex_string(*name, et->name, system_charset_info) &&
|
|
|
|
!sortcmp_lex_string(*db, et->dbname, system_charset_info))
|
|
|
|
{
|
|
|
|
et->free_sp();
|
2005-12-13 19:16:00 +01:00
|
|
|
delete et;
|
2005-12-12 21:19:19 +01:00
|
|
|
evex_queue_delete_element(&EVEX_EQ_NAME, i);
|
|
|
|
// ok, we have cleaned
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
done:
|
|
|
|
if (use_lock)
|
|
|
|
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
|
|
|
|
2005-12-07 19:26:44 +01:00
|
|
|
DBUG_RETURN(0);
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-13 23:10:29 +01:00
|
|
|
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
The function exported to the world for creating of events.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
evex_create_event()
|
|
|
|
thd THD
|
|
|
|
et event's data
|
|
|
|
create_options Options specified when in the query. We are
|
|
|
|
interested whether there is IF NOT EXISTS
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
- in case there is an event with the same name (db) and
|
|
|
|
IF NOT EXISTS is specified, an warning is put into the W stack.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
evex_create_event(THD *thd, event_timed *et, uint create_options)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
DBUG_ENTER("evex_create_event");
|
2005-12-08 00:17:05 +01:00
|
|
|
DBUG_PRINT("enter", ("name: %*s options:%d", et->name.length,
|
|
|
|
et->name.str, create_options));
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
if ((ret = db_create_event(thd, et)) == EVEX_WRITE_ROW_FAILED &&
|
|
|
|
(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
|
|
|
|
{
|
|
|
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
|
|
|
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
|
2005-12-08 00:17:05 +01:00
|
|
|
"EVENT", et->name.str);
|
2005-12-02 13:22:15 +01:00
|
|
|
ret= 0;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
A warning is thrown only when create_options is set to
|
|
|
|
HA_LEX_CREATE_IF_NOT_EXISTS. In this case if EVEX_WRITE_ROW_FAILED,
|
|
|
|
which means that we have duplicated key -> warning. In all
|
|
|
|
other cases -> error.
|
|
|
|
*/
|
|
|
|
if (ret)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
2005-12-08 00:17:05 +01:00
|
|
|
if (evex_is_running && et->status == MYSQL_EVENT_ENABLED)
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
2005-12-08 00:17:05 +01:00
|
|
|
sp_name spn(et->dbname, et->name);
|
2005-12-06 16:15:29 +01:00
|
|
|
ret= evex_load_and_compile_event(thd, &spn, true);
|
2005-12-02 13:22:15 +01:00
|
|
|
}
|
2005-12-06 16:15:29 +01:00
|
|
|
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
done:
|
2005-12-06 16:15:29 +01:00
|
|
|
// No need to close the table, it will be closed in sql_parse::do_command
|
|
|
|
|
2005-12-02 13:22:15 +01:00
|
|
|
DBUG_RETURN(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
The function exported to the world for alteration of events.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
evex_update_event()
|
2005-12-08 00:17:05 +01:00
|
|
|
thd THD
|
|
|
|
et event's data
|
|
|
|
new_name set in case of RENAME TO.
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
NOTES
|
|
|
|
et contains data about dbname and event name.
|
2005-12-06 16:15:29 +01:00
|
|
|
name is the new name of the event, if not null this means
|
2005-12-02 13:22:15 +01:00
|
|
|
that RENAME TO was specified in the query.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
2005-12-08 15:34:11 +01:00
|
|
|
evex_update_event(THD *thd, event_timed *et, sp_name *new_name)
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
|
|
|
int ret, i;
|
|
|
|
bool need_second_pass= true;
|
|
|
|
|
|
|
|
DBUG_ENTER("evex_update_event");
|
2005-12-08 00:17:05 +01:00
|
|
|
DBUG_PRINT("enter", ("name: %*s", et->name.length, et->name.str));
|
2005-12-02 13:22:15 +01:00
|
|
|
|
2005-12-07 19:26:44 +01:00
|
|
|
/*
|
|
|
|
db_update_event() opens & closes the table to prevent
|
2005-12-08 15:34:11 +01:00
|
|
|
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
|
2005-12-07 19:26:44 +01:00
|
|
|
*/
|
2005-12-08 15:34:11 +01:00
|
|
|
if ((ret= db_update_event(thd, et, new_name)))
|
2005-12-07 19:26:44 +01:00
|
|
|
goto done;
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
|
|
|
if (!evex_is_running)
|
2005-12-07 22:29:00 +01:00
|
|
|
UNLOCK_MUTEX_AND_BAIL_OUT(LOCK_evex_running, done);
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
VOID(pthread_mutex_lock(&LOCK_event_arrays));
|
2005-12-08 00:17:05 +01:00
|
|
|
evex_remove_from_cache(&et->dbname, &et->name, false);
|
|
|
|
if (et->status == MYSQL_EVENT_ENABLED)
|
2005-12-08 15:34:11 +01:00
|
|
|
{
|
|
|
|
if (new_name)
|
|
|
|
ret= evex_load_and_compile_event(thd, new_name, false);
|
2005-12-06 16:15:29 +01:00
|
|
|
else
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
2005-12-08 15:34:11 +01:00
|
|
|
sp_name spn(et->dbname, et->name);
|
|
|
|
ret= evex_load_and_compile_event(thd, &spn, false);
|
2005-12-06 16:15:29 +01:00
|
|
|
}
|
2005-12-08 15:34:11 +01:00
|
|
|
if (ret == EVEX_COMPILE_ERROR)
|
|
|
|
my_error(ER_EVENT_COMPILE_ERROR, MYF(0));
|
|
|
|
}
|
2005-12-02 13:22:15 +01:00
|
|
|
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
2005-12-07 22:29:00 +01:00
|
|
|
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
2005-12-02 13:22:15 +01:00
|
|
|
|
2005-12-07 22:29:00 +01:00
|
|
|
done:
|
2005-12-02 13:22:15 +01:00
|
|
|
DBUG_RETURN(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Drops an event
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
evex_drop_event()
|
|
|
|
thd THD
|
|
|
|
et event's name
|
|
|
|
drop_if_exists if set and the event not existing => warning onto the stack
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists)
|
|
|
|
{
|
|
|
|
TABLE *table;
|
2005-12-07 22:29:00 +01:00
|
|
|
int ret= EVEX_OPEN_TABLE_FAILED;
|
2005-12-02 13:22:15 +01:00
|
|
|
bool opened;
|
|
|
|
DBUG_ENTER("evex_drop_event");
|
|
|
|
|
2005-12-16 12:42:39 +01:00
|
|
|
if (evex_open_event_table(thd, TL_WRITE, &table))
|
2005-12-07 22:29:00 +01:00
|
|
|
{
|
|
|
|
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
|
|
|
goto done;
|
|
|
|
}
|
2005-12-02 13:22:15 +01:00
|
|
|
|
2005-12-08 15:34:11 +01:00
|
|
|
if (!(ret= evex_db_find_event_aux(thd, et->dbname, et->name, table)))
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
2005-12-08 00:17:05 +01:00
|
|
|
if ((ret= table->file->delete_row(table->record[0])))
|
2005-12-02 13:22:15 +01:00
|
|
|
{
|
2005-12-07 19:26:44 +01:00
|
|
|
my_error(ER_EVENT_CANNOT_DELETE, MYF(0));
|
2005-12-02 13:22:15 +01:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
2005-12-08 15:34:11 +01:00
|
|
|
else if (ret == EVEX_KEY_NOT_FOUND)
|
|
|
|
{
|
|
|
|
if (drop_if_exists)
|
|
|
|
{
|
|
|
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
2005-12-02 13:22:15 +01:00
|
|
|
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
|
2005-12-08 15:34:11 +01:00
|
|
|
"Event", et->name.str);
|
|
|
|
ret= 0;
|
|
|
|
} else
|
|
|
|
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str);
|
2005-12-02 13:22:15 +01:00
|
|
|
goto done;
|
2005-12-08 15:34:11 +01:00
|
|
|
}
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
|
|
|
if (evex_is_running)
|
2005-12-08 00:17:05 +01:00
|
|
|
ret= evex_remove_from_cache(&et->dbname, &et->name, true);
|
2005-12-02 13:22:15 +01:00
|
|
|
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
|
|
|
|
|
|
|
done:
|
2005-12-07 19:26:44 +01:00
|
|
|
/*
|
|
|
|
No need to close the table, it will be closed in sql_parse::do_command()
|
|
|
|
and evex_remove_from_cache does not try to open a table
|
|
|
|
*/
|
2005-12-02 13:22:15 +01:00
|
|
|
|
|
|
|
DBUG_RETURN(ret);
|
|
|
|
}
|
|
|
|
|