mirror of
https://github.com/MariaDB/server.git
synced 2025-01-30 18:41:56 +01:00
Merge ahristov@bk-internal.mysql.com:/home/bk/mysql-5.1-new
into lmy004.:/work/mysql-5.1-tt-copy-works
This commit is contained in:
commit
a6494fbe31
13 changed files with 348 additions and 168 deletions
|
@ -89,6 +89,21 @@ int my_date_to_str(const MYSQL_TIME *l_time, char *to);
|
||||||
int my_datetime_to_str(const MYSQL_TIME *l_time, char *to);
|
int my_datetime_to_str(const MYSQL_TIME *l_time, char *to);
|
||||||
int my_TIME_to_str(const MYSQL_TIME *l_time, char *to);
|
int my_TIME_to_str(const MYSQL_TIME *l_time, char *to);
|
||||||
|
|
||||||
|
/*
|
||||||
|
The following must be sorted so that simple intervals comes first.
|
||||||
|
(get_interval_value() depends on this)
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum interval_type
|
||||||
|
{
|
||||||
|
INTERVAL_YEAR, INTERVAL_QUARTER, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_HOUR,
|
||||||
|
INTERVAL_MINUTE, INTERVAL_WEEK, INTERVAL_SECOND, INTERVAL_MICROSECOND ,
|
||||||
|
INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE,
|
||||||
|
INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
|
||||||
|
INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND,
|
||||||
|
INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND
|
||||||
|
};
|
||||||
|
|
||||||
C_MODE_END
|
C_MODE_END
|
||||||
|
|
||||||
#endif /* _my_time_h_ */
|
#endif /* _my_time_h_ */
|
||||||
|
|
|
@ -43,6 +43,7 @@ c_tzn="" c_tz="" c_tzt="" c_tztt="" c_tzls="" c_pl=""
|
||||||
i_tzn="" i_tz="" i_tzt="" i_tztt="" i_tzls="" i_pl=""
|
i_tzn="" i_tz="" i_tzt="" i_tztt="" i_tzls="" i_pl=""
|
||||||
c_p="" c_pp=""
|
c_p="" c_pp=""
|
||||||
c_gl="" c_sl=""
|
c_gl="" c_sl=""
|
||||||
|
c_ev= ""
|
||||||
|
|
||||||
# Check for old tables
|
# Check for old tables
|
||||||
if test ! -f $mdata/db.frm
|
if test ! -f $mdata/db.frm
|
||||||
|
|
11
sql/event.cc
11
sql/event.cc
|
@ -88,8 +88,14 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
|
||||||
int
|
int
|
||||||
my_time_compare(TIME *a, TIME *b)
|
my_time_compare(TIME *a, TIME *b)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef ENABLE_WHEN_WE_HAVE_MILLISECOND_IN_TIMESTAMPS
|
||||||
my_ulonglong a_t= TIME_to_ulonglong_datetime(a)*100L + a->second_part;
|
my_ulonglong a_t= TIME_to_ulonglong_datetime(a)*100L + a->second_part;
|
||||||
my_ulonglong b_t= TIME_to_ulonglong_datetime(b)*100L + b->second_part;
|
my_ulonglong b_t= TIME_to_ulonglong_datetime(b)*100L + b->second_part;
|
||||||
|
#else
|
||||||
|
my_ulonglong a_t= TIME_to_ulonglong_datetime(a);
|
||||||
|
my_ulonglong b_t= TIME_to_ulonglong_datetime(b);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (a_t > b_t)
|
if (a_t > b_t)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -355,12 +361,17 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
|
||||||
|
|
||||||
DBUG_PRINT("info", ("check existance of an event with the same name"));
|
DBUG_PRINT("info", ("check existance of an event with the same name"));
|
||||||
if (!evex_db_find_event_aux(thd, et->dbname, et->name, table))
|
if (!evex_db_find_event_aux(thd, et->dbname, et->name, table))
|
||||||
|
{
|
||||||
|
if (create_if_not)
|
||||||
{
|
{
|
||||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||||
ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
|
ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
|
||||||
et->name.str);
|
et->name.str);
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), et->name.str);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
DBUG_PRINT("info", ("non-existant, go forward"));
|
DBUG_PRINT("info", ("non-existant, go forward"));
|
||||||
if ((ret= sp_use_new_db(thd, et->dbname.str,olddb, sizeof(olddb),0, &dbchanged)))
|
if ((ret= sp_use_new_db(thd, et->dbname.str,olddb, sizeof(olddb),0, &dbchanged)))
|
||||||
|
|
|
@ -148,7 +148,7 @@ public:
|
||||||
compute_next_execution_time();
|
compute_next_execution_time();
|
||||||
|
|
||||||
void
|
void
|
||||||
mark_last_executed();
|
mark_last_executed(THD *thd);
|
||||||
|
|
||||||
int
|
int
|
||||||
drop(THD *thd);
|
drop(THD *thd);
|
||||||
|
|
|
@ -334,9 +334,19 @@ event_executor_main(void *arg)
|
||||||
{
|
{
|
||||||
pthread_t th;
|
pthread_t th;
|
||||||
|
|
||||||
DBUG_PRINT("evex main thread",("mark_last_executed"));
|
DBUG_PRINT("evex main thread", ("[%10s] this exec at [%llu]", et->name.str,
|
||||||
et->mark_last_executed();
|
TIME_to_ulonglong_datetime(&et->execute_at)));
|
||||||
et->compute_next_execution_time();
|
et->mark_last_executed(thd);
|
||||||
|
if (et->compute_next_execution_time())
|
||||||
|
{
|
||||||
|
sql_print_error("Error while computing time of %s.%s . "
|
||||||
|
"Disabling after execution.",
|
||||||
|
et->dbname.str, et->name.str);
|
||||||
|
et->status= MYSQL_EVENT_DISABLED;
|
||||||
|
}
|
||||||
|
DBUG_PRINT("evex main thread", ("[%10s] next exec at [%llu]", et->name.str,
|
||||||
|
TIME_to_ulonglong_datetime(&et->execute_at)));
|
||||||
|
|
||||||
et->update_fields(thd);
|
et->update_fields(thd);
|
||||||
DBUG_PRINT("info", (" Spawning a thread %d", ++iter_num));
|
DBUG_PRINT("info", (" Spawning a thread %d", ++iter_num));
|
||||||
#ifndef DBUG_FAULTY_THR
|
#ifndef DBUG_FAULTY_THR
|
||||||
|
@ -605,7 +615,12 @@ evex_load_events_from_db(THD *thd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// let's find when to be executed
|
// let's find when to be executed
|
||||||
et->compute_next_execution_time();
|
if (et->compute_next_execution_time())
|
||||||
|
{
|
||||||
|
sql_print_error("Error while computing execution time of %s.%s. Skipping",
|
||||||
|
et->dbname.str, et->name.str);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
DBUG_PRINT("evex_load_events_from_db", ("Adding to the exec list."));
|
DBUG_PRINT("evex_load_events_from_db", ("Adding to the exec list."));
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ enum evex_table_field
|
||||||
|
|
||||||
#define EVEX_DB_FIELD_LEN 64
|
#define EVEX_DB_FIELD_LEN 64
|
||||||
#define EVEX_NAME_FIELD_LEN 64
|
#define EVEX_NAME_FIELD_LEN 64
|
||||||
|
#define EVEX_MAX_INTERVAL_VALUE 2147483647L
|
||||||
|
|
||||||
int
|
int
|
||||||
my_time_compare(TIME *a, TIME *b);
|
my_time_compare(TIME *a, TIME *b);
|
||||||
|
|
|
@ -191,16 +191,78 @@ int
|
||||||
event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
|
event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
|
||||||
{
|
{
|
||||||
longlong tmp;
|
longlong tmp;
|
||||||
|
String value;
|
||||||
|
INTERVAL interval;
|
||||||
|
|
||||||
DBUG_ENTER("event_timed::init_interval");
|
DBUG_ENTER("event_timed::init_interval");
|
||||||
|
|
||||||
if (expr->fix_fields(thd, &expr))
|
if (expr->fix_fields(thd, &expr))
|
||||||
DBUG_RETURN(EVEX_PARSE_ERROR);
|
DBUG_RETURN(EVEX_PARSE_ERROR);
|
||||||
|
|
||||||
if ((tmp= expr->val_int()) <= 0)
|
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);
|
||||||
|
|
||||||
|
expression= 0;
|
||||||
|
|
||||||
|
switch (new_interval) {
|
||||||
|
case INTERVAL_YEAR:
|
||||||
|
expression= interval.year;
|
||||||
|
break;
|
||||||
|
case INTERVAL_QUARTER:
|
||||||
|
case INTERVAL_MONTH:
|
||||||
|
expression= interval.month;
|
||||||
|
break;
|
||||||
|
case INTERVAL_WEEK:
|
||||||
|
case INTERVAL_DAY:
|
||||||
|
expression= interval.day;
|
||||||
|
break;
|
||||||
|
case INTERVAL_HOUR:
|
||||||
|
expression= interval.hour;
|
||||||
|
break;
|
||||||
|
case INTERVAL_MINUTE:
|
||||||
|
expression= interval.minute;
|
||||||
|
break;
|
||||||
|
case INTERVAL_SECOND:
|
||||||
|
expression= interval.second;
|
||||||
|
break;
|
||||||
|
case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
|
||||||
|
expression= interval.year* 12 + interval.month;
|
||||||
|
break;
|
||||||
|
case INTERVAL_DAY_HOUR:
|
||||||
|
expression= interval.day* 24 + interval.hour;
|
||||||
|
break;
|
||||||
|
case INTERVAL_DAY_MINUTE:
|
||||||
|
expression= (interval.day* 24 + interval.hour) * 60 + interval.minute;
|
||||||
|
break;
|
||||||
|
case INTERVAL_HOUR_SECOND: // day is anyway 0
|
||||||
|
case INTERVAL_DAY_SECOND:
|
||||||
|
/* 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:
|
||||||
|
expression= ((((interval.day*24) + interval.hour)*60+interval.minute)*60 +
|
||||||
|
interval.second) * 1000000L + interval.second_part;
|
||||||
|
break;
|
||||||
|
case INTERVAL_HOUR_MINUTE:
|
||||||
|
expression= interval.hour * 60 + interval.minute;
|
||||||
|
break;
|
||||||
|
case INTERVAL_MINUTE_SECOND:
|
||||||
|
expression= interval.minute * 60 + interval.second;
|
||||||
|
break;
|
||||||
|
case INTERVAL_SECOND_MICROSECOND:
|
||||||
|
expression= interval.second * 1000000L + interval.second_part;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (interval.neg || expression > EVEX_MAX_INTERVAL_VALUE)
|
||||||
DBUG_RETURN(EVEX_BAD_PARAMS);
|
DBUG_RETURN(EVEX_BAD_PARAMS);
|
||||||
|
|
||||||
expression= tmp;
|
this->interval= new_interval;
|
||||||
interval= new_interval;
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +417,7 @@ event_timed::init_definer(THD *thd)
|
||||||
Loads an event from a row from mysql.event
|
Loads an event from a row from mysql.event
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
event_timed::load_from_row()
|
event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
|
||||||
|
|
||||||
REMARKS
|
REMARKS
|
||||||
This method is silent on errors and should behave like that. Callers
|
This method is silent on errors and should behave like that. Callers
|
||||||
|
@ -499,8 +561,83 @@ error:
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Note: In the comments this->ends is referenced as m_ends
|
Computes the sum of a timestamp plus interval
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
get_next_time(TIME *start, int interval_value, interval_type interval)
|
||||||
|
|
||||||
|
next - the sum
|
||||||
|
start - add interval_value to this time
|
||||||
|
i_value - quantity of time type interval to add
|
||||||
|
i_type - type of interval to add (SECOND, MINUTE, HOUR, WEEK ...)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static
|
||||||
|
bool get_next_time(TIME *next, TIME *start, int i_value, interval_type i_type)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
INTERVAL interval;
|
||||||
|
TIME tmp;
|
||||||
|
|
||||||
|
bzero(&interval, sizeof(interval));
|
||||||
|
|
||||||
|
switch (i_type) {
|
||||||
|
case INTERVAL_YEAR:
|
||||||
|
interval.year= (ulong) i_value;
|
||||||
|
break;
|
||||||
|
case INTERVAL_QUARTER:
|
||||||
|
interval.month= (ulong)(i_value*3);
|
||||||
|
break;
|
||||||
|
case INTERVAL_YEAR_MONTH:
|
||||||
|
case INTERVAL_MONTH:
|
||||||
|
interval.month= (ulong) i_value;
|
||||||
|
break;
|
||||||
|
case INTERVAL_WEEK:
|
||||||
|
interval.day= (ulong)(i_value*7);
|
||||||
|
break;
|
||||||
|
case INTERVAL_DAY:
|
||||||
|
interval.day= (ulong) i_value;
|
||||||
|
break;
|
||||||
|
case INTERVAL_DAY_HOUR:
|
||||||
|
case INTERVAL_HOUR:
|
||||||
|
interval.hour= (ulong) i_value;
|
||||||
|
break;
|
||||||
|
case INTERVAL_DAY_MINUTE:
|
||||||
|
case INTERVAL_HOUR_MINUTE:
|
||||||
|
case INTERVAL_MINUTE:
|
||||||
|
interval.minute=i_value;
|
||||||
|
break;
|
||||||
|
case INTERVAL_DAY_SECOND:
|
||||||
|
case INTERVAL_HOUR_SECOND:
|
||||||
|
case INTERVAL_MINUTE_SECOND:
|
||||||
|
case INTERVAL_SECOND:
|
||||||
|
interval.second=i_value;
|
||||||
|
break;
|
||||||
|
case INTERVAL_DAY_MICROSECOND:
|
||||||
|
case INTERVAL_HOUR_MICROSECOND:
|
||||||
|
case INTERVAL_MINUTE_MICROSECOND:
|
||||||
|
case INTERVAL_SECOND_MICROSECOND:
|
||||||
|
case INTERVAL_MICROSECOND:
|
||||||
|
interval.second_part=i_value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tmp= *start;
|
||||||
|
if (!(ret= date_add_interval(&tmp, i_type, interval)))
|
||||||
|
*next= tmp;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Computes next execution time.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
event_timed::compute_next_execution_time()
|
||||||
|
|
||||||
|
REMARKS:
|
||||||
|
The time is set in execute_at, if no more executions the latter is set to
|
||||||
|
0000-00-00.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -605,14 +742,13 @@ event_timed::compute_next_execution_time()
|
||||||
execute_at= time_now;
|
execute_at= time_now;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
my_time_t last, ll_ends;
|
TIME next_exec;
|
||||||
|
|
||||||
|
if (get_next_time(&next_exec, &last_executed, expression, interval))
|
||||||
|
goto err;
|
||||||
|
|
||||||
// There was previous execution
|
// There was previous execution
|
||||||
last= sec_since_epoch_TIME(&last_executed) + expression;
|
if (my_time_compare(&ends, &next_exec) == -1)
|
||||||
ll_ends= sec_since_epoch_TIME(&ends);
|
|
||||||
//now convert back to TIME
|
|
||||||
//ToDo Andrey: maybe check for error here?
|
|
||||||
if (ll_ends < last)
|
|
||||||
{
|
{
|
||||||
// Next execution after ends. No more executions
|
// Next execution after ends. No more executions
|
||||||
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||||
|
@ -620,7 +756,7 @@ event_timed::compute_next_execution_time()
|
||||||
dropped= true;
|
dropped= true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
my_tz_UTC->gmt_sec_to_TIME(&execute_at, last);
|
execute_at= next_exec;
|
||||||
}
|
}
|
||||||
goto ret;
|
goto ret;
|
||||||
}
|
}
|
||||||
|
@ -628,14 +764,14 @@ event_timed::compute_next_execution_time()
|
||||||
{
|
{
|
||||||
// both starts and m_ends are not set, se we schedule for the next
|
// both starts and m_ends are not set, se we schedule for the next
|
||||||
// based on last_executed
|
// based on last_executed
|
||||||
if (!last_executed.year)
|
if (last_executed.year)
|
||||||
|
{
|
||||||
|
if (get_next_time(&execute_at, &last_executed, expression, interval))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
else
|
||||||
//last_executed not set. Schedule the event for now
|
//last_executed not set. Schedule the event for now
|
||||||
execute_at= time_now;
|
execute_at= time_now;
|
||||||
else
|
|
||||||
//ToDo Andrey: maybe check for error here?
|
|
||||||
my_tz_UTC->gmt_sec_to_TIME(&execute_at,
|
|
||||||
sec_since_epoch_TIME(&last_executed) + expression);
|
|
||||||
goto ret;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -648,17 +784,13 @@ event_timed::compute_next_execution_time()
|
||||||
Hence schedule for starts + m_expression in case last_executed
|
Hence schedule for starts + m_expression in case last_executed
|
||||||
is not set, otherwise to last_executed + m_expression
|
is not set, otherwise to last_executed + m_expression
|
||||||
*/
|
*/
|
||||||
my_time_t last;
|
|
||||||
|
|
||||||
//convert either last_executed or starts to seconds
|
|
||||||
if (last_executed.year)
|
if (last_executed.year)
|
||||||
last= sec_since_epoch_TIME(&last_executed) + expression;
|
{
|
||||||
|
if (get_next_time(&execute_at, &last_executed, expression, interval))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
last= sec_since_epoch_TIME(&starts);
|
execute_at= starts;
|
||||||
|
|
||||||
//now convert back to TIME
|
|
||||||
//ToDo Andrey: maybe check for error here?
|
|
||||||
my_tz_UTC->gmt_sec_to_TIME(&execute_at, last);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -668,25 +800,24 @@ event_timed::compute_next_execution_time()
|
||||||
Hence check for m_last_execute and increment with m_expression.
|
Hence check for m_last_execute and increment with m_expression.
|
||||||
If last_executed is not set then schedule for now
|
If last_executed is not set then schedule for now
|
||||||
*/
|
*/
|
||||||
my_time_t last, ll_ends;
|
|
||||||
|
|
||||||
if (!last_executed.year)
|
if (!last_executed.year)
|
||||||
execute_at= time_now;
|
execute_at= time_now;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
last= sec_since_epoch_TIME(&last_executed);
|
TIME next_exec;
|
||||||
ll_ends= sec_since_epoch_TIME(&ends);
|
|
||||||
last+= expression;
|
if (get_next_time(&next_exec, &last_executed, expression, interval))
|
||||||
//now convert back to TIME
|
goto err;
|
||||||
//ToDo Andrey: maybe check for error here?
|
|
||||||
if (ll_ends < last)
|
if (my_time_compare(&ends, &next_exec) == -1)
|
||||||
{
|
{
|
||||||
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||||
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
|
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
|
||||||
dropped= true;
|
dropped= true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
my_tz_UTC->gmt_sec_to_TIME(&execute_at, last);
|
execute_at= next_exec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
goto ret;
|
goto ret;
|
||||||
|
@ -694,17 +825,18 @@ event_timed::compute_next_execution_time()
|
||||||
ret:
|
ret:
|
||||||
|
|
||||||
DBUG_RETURN(false);
|
DBUG_RETURN(false);
|
||||||
|
err:
|
||||||
|
DBUG_RETURN(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
event_timed::mark_last_executed()
|
event_timed::mark_last_executed(THD *thd)
|
||||||
{
|
{
|
||||||
TIME time_now;
|
TIME time_now;
|
||||||
my_time_t now;
|
|
||||||
|
|
||||||
time((time_t *)&now);
|
thd->end_time();
|
||||||
my_tz_UTC->gmt_sec_to_TIME(&time_now, now);
|
my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start());
|
||||||
|
|
||||||
last_executed= time_now; // was execute_at
|
last_executed= time_now; // was execute_at
|
||||||
#ifdef ANDREY_0
|
#ifdef ANDREY_0
|
||||||
|
|
|
@ -1135,7 +1135,7 @@ longlong Item_func_time_to_sec::val_int()
|
||||||
To make code easy, allow interval objects without separators.
|
To make code easy, allow interval objects without separators.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool get_interval_value(Item *args,interval_type int_type,
|
bool get_interval_value(Item *args,interval_type int_type,
|
||||||
String *str_value, INTERVAL *interval)
|
String *str_value, INTERVAL *interval)
|
||||||
{
|
{
|
||||||
ulonglong array[5];
|
ulonglong array[5];
|
||||||
|
@ -1994,110 +1994,15 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
|
||||||
long period,sign;
|
long period,sign;
|
||||||
INTERVAL interval;
|
INTERVAL interval;
|
||||||
|
|
||||||
ltime->neg= 0;
|
|
||||||
if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE) ||
|
if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE) ||
|
||||||
get_interval_value(args[1],int_type,&value,&interval))
|
get_interval_value(args[1],int_type,&value,&interval))
|
||||||
goto null_date;
|
goto null_date;
|
||||||
sign= (interval.neg ? -1 : 1);
|
|
||||||
if (date_sub_interval)
|
if (date_sub_interval)
|
||||||
sign = -sign;
|
interval.neg = !interval.neg;
|
||||||
|
|
||||||
null_value=0;
|
return (null_value= date_add_interval(ltime, int_type, interval));
|
||||||
switch (int_type) {
|
|
||||||
case INTERVAL_SECOND:
|
|
||||||
case INTERVAL_SECOND_MICROSECOND:
|
|
||||||
case INTERVAL_MICROSECOND:
|
|
||||||
case INTERVAL_MINUTE:
|
|
||||||
case INTERVAL_HOUR:
|
|
||||||
case INTERVAL_MINUTE_MICROSECOND:
|
|
||||||
case INTERVAL_MINUTE_SECOND:
|
|
||||||
case INTERVAL_HOUR_MICROSECOND:
|
|
||||||
case INTERVAL_HOUR_SECOND:
|
|
||||||
case INTERVAL_HOUR_MINUTE:
|
|
||||||
case INTERVAL_DAY_MICROSECOND:
|
|
||||||
case INTERVAL_DAY_SECOND:
|
|
||||||
case INTERVAL_DAY_MINUTE:
|
|
||||||
case INTERVAL_DAY_HOUR:
|
|
||||||
{
|
|
||||||
longlong sec, days, daynr, microseconds, extra_sec;
|
|
||||||
ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date
|
|
||||||
microseconds= ltime->second_part + sign*interval.second_part;
|
|
||||||
extra_sec= microseconds/1000000L;
|
|
||||||
microseconds= microseconds%1000000L;
|
|
||||||
|
|
||||||
sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
|
|
||||||
ltime->second +
|
|
||||||
sign* (longlong) (interval.day*3600*24L +
|
|
||||||
interval.hour*LL(3600)+interval.minute*LL(60)+
|
|
||||||
interval.second))+ extra_sec;
|
|
||||||
if (microseconds < 0)
|
|
||||||
{
|
|
||||||
microseconds+= LL(1000000);
|
|
||||||
sec--;
|
|
||||||
}
|
|
||||||
days= sec/(3600*LL(24));
|
|
||||||
sec-= days*3600*LL(24);
|
|
||||||
if (sec < 0)
|
|
||||||
{
|
|
||||||
days--;
|
|
||||||
sec+= 3600*LL(24);
|
|
||||||
}
|
|
||||||
ltime->second_part= (uint) microseconds;
|
|
||||||
ltime->second= (uint) (sec % 60);
|
|
||||||
ltime->minute= (uint) (sec/60 % 60);
|
|
||||||
ltime->hour= (uint) (sec/3600);
|
|
||||||
daynr= calc_daynr(ltime->year,ltime->month,1) + days;
|
|
||||||
/* Day number from year 0 to 9999-12-31 */
|
|
||||||
if ((ulonglong) daynr >= MAX_DAY_NUMBER)
|
|
||||||
goto invalid_date;
|
|
||||||
get_date_from_daynr((long) daynr, <ime->year, <ime->month,
|
|
||||||
<ime->day);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case INTERVAL_DAY:
|
|
||||||
case INTERVAL_WEEK:
|
|
||||||
period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
|
|
||||||
sign * (long) interval.day);
|
|
||||||
/* Daynumber from year 0 to 9999-12-31 */
|
|
||||||
if ((ulong) period >= MAX_DAY_NUMBER)
|
|
||||||
goto invalid_date;
|
|
||||||
get_date_from_daynr((long) period,<ime->year,<ime->month,<ime->day);
|
|
||||||
break;
|
|
||||||
case INTERVAL_YEAR:
|
|
||||||
ltime->year+= sign * (long) interval.year;
|
|
||||||
if ((ulong) ltime->year >= 10000L)
|
|
||||||
goto invalid_date;
|
|
||||||
if (ltime->month == 2 && ltime->day == 29 &&
|
|
||||||
calc_days_in_year(ltime->year) != 366)
|
|
||||||
ltime->day=28; // Was leap-year
|
|
||||||
break;
|
|
||||||
case INTERVAL_YEAR_MONTH:
|
|
||||||
case INTERVAL_QUARTER:
|
|
||||||
case INTERVAL_MONTH:
|
|
||||||
period= (ltime->year*12 + sign * (long) interval.year*12 +
|
|
||||||
ltime->month-1 + sign * (long) interval.month);
|
|
||||||
if ((ulong) period >= 120000L)
|
|
||||||
goto invalid_date;
|
|
||||||
ltime->year= (uint) (period / 12);
|
|
||||||
ltime->month= (uint) (period % 12L)+1;
|
|
||||||
/* Adjust day if the new month doesn't have enough days */
|
|
||||||
if (ltime->day > days_in_month[ltime->month-1])
|
|
||||||
{
|
|
||||||
ltime->day = days_in_month[ltime->month-1];
|
|
||||||
if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
|
|
||||||
ltime->day++; // Leap-year
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
goto null_date;
|
|
||||||
}
|
|
||||||
return 0; // Ok
|
|
||||||
|
|
||||||
invalid_date:
|
|
||||||
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
||||||
ER_DATETIME_FUNCTION_OVERFLOW,
|
|
||||||
ER(ER_DATETIME_FUNCTION_OVERFLOW),
|
|
||||||
"datetime");
|
|
||||||
null_date:
|
null_date:
|
||||||
return (null_value=1);
|
return (null_value=1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,9 @@ enum date_time_format_types
|
||||||
TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND
|
TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool get_interval_value(Item *args,interval_type int_type,
|
||||||
|
String *str_value, INTERVAL *interval);
|
||||||
|
|
||||||
class Item_func_period_add :public Item_int_func
|
class Item_func_period_add :public Item_int_func
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -626,20 +629,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
The following must be sorted so that simple intervals comes first.
|
|
||||||
(get_interval_value() depends on this)
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum interval_type
|
|
||||||
{
|
|
||||||
INTERVAL_YEAR, INTERVAL_QUARTER, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_HOUR,
|
|
||||||
INTERVAL_MINUTE, INTERVAL_WEEK, INTERVAL_SECOND, INTERVAL_MICROSECOND ,
|
|
||||||
INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE,
|
|
||||||
INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
|
|
||||||
INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND,
|
|
||||||
INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND
|
|
||||||
};
|
|
||||||
|
|
||||||
class Item_date_add_interval :public Item_date_func
|
class Item_date_add_interval :public Item_date_func
|
||||||
{
|
{
|
||||||
|
|
|
@ -1532,6 +1532,9 @@ void calc_time_from_sec(TIME *to, long seconds, long microseconds);
|
||||||
void make_truncated_value_warning(THD *thd, const char *str_val,
|
void make_truncated_value_warning(THD *thd, const char *str_val,
|
||||||
uint str_length, timestamp_type time_type,
|
uint str_length, timestamp_type time_type,
|
||||||
const char *field_name);
|
const char *field_name);
|
||||||
|
|
||||||
|
bool date_add_interval(TIME *ltime, interval_type int_type, INTERVAL interval);
|
||||||
|
|
||||||
extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
|
extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
|
||||||
const char *format_str,
|
const char *format_str,
|
||||||
uint format_length);
|
uint format_length);
|
||||||
|
|
|
@ -5769,8 +5769,8 @@ ER_EVENT_CANT_ALTER
|
||||||
eng "Failed to alter event '%-.64s'"
|
eng "Failed to alter event '%-.64s'"
|
||||||
ER_EVENT_DROP_FAILED
|
ER_EVENT_DROP_FAILED
|
||||||
eng "Failed to drop %s"
|
eng "Failed to drop %s"
|
||||||
ER_EVENT_INTERVAL_NOT_POSITIVE
|
ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG
|
||||||
eng "INTERVAL must be positive"
|
eng "INTERVAL is either not positive or too big"
|
||||||
ER_EVENT_ENDS_BEFORE_STARTS
|
ER_EVENT_ENDS_BEFORE_STARTS
|
||||||
eng "ENDS must be after STARTS"
|
eng "ENDS must be after STARTS"
|
||||||
ER_EVENT_EXEC_TIME_IN_THE_PAST
|
ER_EVENT_EXEC_TIME_IN_THE_PAST
|
||||||
|
|
|
@ -1418,7 +1418,7 @@ ev_schedule_time: EVERY_SYM expr interval
|
||||||
YYABORT;
|
YYABORT;
|
||||||
break;
|
break;
|
||||||
case EVEX_BAD_PARAMS:
|
case EVEX_BAD_PARAMS:
|
||||||
my_error(ER_EVENT_INTERVAL_NOT_POSITIVE, MYF(0));
|
my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
|
||||||
YYABORT;
|
YYABORT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
108
sql/time.cc
108
sql/time.cc
|
@ -724,5 +724,113 @@ void make_truncated_value_warning(THD *thd, const char *str_val,
|
||||||
ER_TRUNCATED_WRONG_VALUE, warn_buff);
|
ER_TRUNCATED_WRONG_VALUE, warn_buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAX_DAY_NUMBER 3652424L
|
||||||
|
|
||||||
|
bool date_add_interval(TIME *ltime, interval_type int_type, INTERVAL interval)
|
||||||
|
{
|
||||||
|
long period, sign;
|
||||||
|
|
||||||
|
ltime->neg= 0;
|
||||||
|
|
||||||
|
sign= (interval.neg ? -1 : 1);
|
||||||
|
|
||||||
|
switch (int_type) {
|
||||||
|
case INTERVAL_SECOND:
|
||||||
|
case INTERVAL_SECOND_MICROSECOND:
|
||||||
|
case INTERVAL_MICROSECOND:
|
||||||
|
case INTERVAL_MINUTE:
|
||||||
|
case INTERVAL_HOUR:
|
||||||
|
case INTERVAL_MINUTE_MICROSECOND:
|
||||||
|
case INTERVAL_MINUTE_SECOND:
|
||||||
|
case INTERVAL_HOUR_MICROSECOND:
|
||||||
|
case INTERVAL_HOUR_SECOND:
|
||||||
|
case INTERVAL_HOUR_MINUTE:
|
||||||
|
case INTERVAL_DAY_MICROSECOND:
|
||||||
|
case INTERVAL_DAY_SECOND:
|
||||||
|
case INTERVAL_DAY_MINUTE:
|
||||||
|
case INTERVAL_DAY_HOUR:
|
||||||
|
{
|
||||||
|
longlong sec, days, daynr, microseconds, extra_sec;
|
||||||
|
ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date
|
||||||
|
microseconds= ltime->second_part + sign*interval.second_part;
|
||||||
|
extra_sec= microseconds/1000000L;
|
||||||
|
microseconds= microseconds%1000000L;
|
||||||
|
|
||||||
|
sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
|
||||||
|
ltime->second +
|
||||||
|
sign* (longlong) (interval.day*3600*24L +
|
||||||
|
interval.hour*LL(3600)+interval.minute*LL(60)+
|
||||||
|
interval.second))+ extra_sec;
|
||||||
|
if (microseconds < 0)
|
||||||
|
{
|
||||||
|
microseconds+= LL(1000000);
|
||||||
|
sec--;
|
||||||
|
}
|
||||||
|
days= sec/(3600*LL(24));
|
||||||
|
sec-= days*3600*LL(24);
|
||||||
|
if (sec < 0)
|
||||||
|
{
|
||||||
|
days--;
|
||||||
|
sec+= 3600*LL(24);
|
||||||
|
}
|
||||||
|
ltime->second_part= (uint) microseconds;
|
||||||
|
ltime->second= (uint) (sec % 60);
|
||||||
|
ltime->minute= (uint) (sec/60 % 60);
|
||||||
|
ltime->hour= (uint) (sec/3600);
|
||||||
|
daynr= calc_daynr(ltime->year,ltime->month,1) + days;
|
||||||
|
/* Day number from year 0 to 9999-12-31 */
|
||||||
|
if ((ulonglong) daynr >= MAX_DAY_NUMBER)
|
||||||
|
goto invalid_date;
|
||||||
|
get_date_from_daynr((long) daynr, <ime->year, <ime->month,
|
||||||
|
<ime->day);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INTERVAL_DAY:
|
||||||
|
case INTERVAL_WEEK:
|
||||||
|
period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
|
||||||
|
sign * (long) interval.day);
|
||||||
|
/* Daynumber from year 0 to 9999-12-31 */
|
||||||
|
if ((ulong) period >= MAX_DAY_NUMBER)
|
||||||
|
goto invalid_date;
|
||||||
|
get_date_from_daynr((long) period,<ime->year,<ime->month,<ime->day);
|
||||||
|
break;
|
||||||
|
case INTERVAL_YEAR:
|
||||||
|
ltime->year+= sign * (long) interval.year;
|
||||||
|
if ((ulong) ltime->year >= 10000L)
|
||||||
|
goto invalid_date;
|
||||||
|
if (ltime->month == 2 && ltime->day == 29 &&
|
||||||
|
calc_days_in_year(ltime->year) != 366)
|
||||||
|
ltime->day=28; // Was leap-year
|
||||||
|
break;
|
||||||
|
case INTERVAL_YEAR_MONTH:
|
||||||
|
case INTERVAL_QUARTER:
|
||||||
|
case INTERVAL_MONTH:
|
||||||
|
period= (ltime->year*12 + sign * (long) interval.year*12 +
|
||||||
|
ltime->month-1 + sign * (long) interval.month);
|
||||||
|
if ((ulong) period >= 120000L)
|
||||||
|
goto invalid_date;
|
||||||
|
ltime->year= (uint) (period / 12);
|
||||||
|
ltime->month= (uint) (period % 12L)+1;
|
||||||
|
/* Adjust day if the new month doesn't have enough days */
|
||||||
|
if (ltime->day > days_in_month[ltime->month-1])
|
||||||
|
{
|
||||||
|
ltime->day = days_in_month[ltime->month-1];
|
||||||
|
if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
|
||||||
|
ltime->day++; // Leap-year
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0; // Ok
|
||||||
|
|
||||||
|
invalid_date:
|
||||||
|
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||||
|
ER_DATETIME_FUNCTION_OVERFLOW,
|
||||||
|
ER(ER_DATETIME_FUNCTION_OVERFLOW),
|
||||||
|
"datetime");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue