summaryrefslogtreecommitdiff
path: root/sql/time.cc
diff options
context:
space:
mode:
authorandrey@lmy004. <>2006-01-18 20:41:22 +0100
committerandrey@lmy004. <>2006-01-18 20:41:22 +0100
commit0322cb1df817e4a1bdc490746d351a533442eba4 (patch)
tree364b1773d1b0b50d5005939089eefee7bc15af75 /sql/time.cc
parent3eba9695d0340a9b8a618faf77b50c8f3bd92eb9 (diff)
downloadmariadb-git-0322cb1df817e4a1bdc490746d351a533442eba4.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.
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