summaryrefslogtreecommitdiff
path: root/sql/time.cc
diff options
context:
space:
mode:
authorunknown <andrey@lmy004.>2006-01-18 20:41:22 +0100
committerunknown <andrey@lmy004.>2006-01-18 20:41:22 +0100
commit6bd58a2a3ce27eb744a8d35893f5bfefd9e173dd (patch)
tree364b1773d1b0b50d5005939089eefee7bc15af75 /sql/time.cc
parentef3a610638a4d0742a8b4a33e329f5f963e55bec (diff)
downloadmariadb-git-6bd58a2a3ce27eb744a8d35893f5bfefd9e173dd.tar.gz
- fix bug #16435 (Weekly events execute every second) (WL#1034 Internal CRON)
Before the interval expression was considered to be in seconds, now it is just a number and the type of interval is considered. - this changeset introduces also fix for bug#16432 (Events: error re interval misrepresents the facts) the code of event_timed::set_interval() was refactored anyway so it is meaningful to fix the bug in the same changeset. include/my_time.h: - move enum interval_type to include/my_time.h so it can be used by functions in the whole server sql/event.cc: - don't use second_part - fix small problem with create event xyz, when xyz exists -> make it error instead of warning if create_if_not is false. sql/event.h: pass thd to mark_last_executed() to be able to call thd->end_time() sql/event_executor.cc: - pass thd to event_timed::compute_next_execution_time() - a bit more DBUG info in the server log - handle error returned by event_timed::compute_next_execution_time() sql/event_priv.h: - define the maximal possible value for interval_value sql/event_timed.cc: - more docs - add static get_next_time() which sums a TIME with an interval - fix bug #16435 (Weekly events execute every second) Before the interval expression was considered to be in seconds, now it is just a number and the type of interval is considered. - fix for bug#16432 (Events: error re interval misrepresents the facts) (return an error if a value is too big or is negative - errmsg changed) sql/item_timefunc.cc: - export get_interval_date() - refactor Item_date_add_interval::get_date() and extract the core to date_add_interval() in time.cc so it can be reused by the scheduler code in event_timed.cc sql/item_timefunc.h: - export get_interval_value() so it can be reused in event_timed.cc in function static get_next_time() - move enum interval_type to include/my_time.h so it can be used by functions in the whole server sql/mysql_priv.h: export the new function date_add_interval() added to time.cc sql/share/errmsg.txt: - change error message to be appropriate as fix for bug#16432 (Events: error re interval misrepresents the facts) sql/sql_yacc.yy: - change error message to be appropriate as fix for bug#16432 (Events: error re interval misrepresents the facts) sql/time.cc: extract the core of Item_date_add_interval::get_date() to a function per Serg's request. The code can be reused to add und substract interval from a date.
Diffstat (limited to 'sql/time.cc')
-rw-r--r--sql/time.cc108
1 files changed, 108 insertions, 0 deletions
diff --git a/sql/time.cc b/sql/time.cc
index 480cafaab34..efe1cbf1c09 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -724,5 +724,113 @@ void make_truncated_value_warning(THD *thd, const char *str_val,
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, &ltime->year, &ltime->month,
+ &ltime->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,&ltime->year,&ltime->month,&ltime->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