Commit 4d97b06b authored by Joerg Bruehe's avatar Joerg Bruehe

Backport of a 5.0.74 fix into 5.0.72sp1:

Bug #39920: MySQL cannot deal with Leap Second expression in string literal.

Updated MySQL time handling code to react correctly on UTC leap second additions.
MySQL functions that return the OS current time, like e.g. CURDATE(), NOW() etc
will return :59:59 instead of :59:60 or 59:61.
As a result the reader will receive :59:59 for 2 or 3 consecutive seconds
during the leap second.

Original changesets:
> revision-id: kgeorge@mysql.com-20081201141835-rg8nnnadujj5wl9f
> parent: gshchepa@mysql.com-20081114172557-xh0jlzwal8ze3cy6
> committer: Georgi Kodinov <kgeorge@mysql.com>
> branch nick: B39920-5.0-bugteam
> timestamp: Mon 2008-12-01 16:18:35 +0200

> revision-id: kgeorge@mysql.com-20081201154106-c310zzy5or043rqa
> parent: kgeorge@mysql.com-20081201145656-6kjq91oga5nxbbob
> committer: Georgi Kodinov <kgeorge@mysql.com>
> branch nick: B39920-merge-5.0-bugteam
> timestamp: Mon 2008-12-01 17:41:06 +0200
parent 037093b6
...@@ -110,7 +110,7 @@ i ts ...@@ -110,7 +110,7 @@ i ts
362793610 1981-07-01 04:00:00 362793610 1981-07-01 04:00:00
select from_unixtime(362793609); select from_unixtime(362793609);
from_unixtime(362793609) from_unixtime(362793609)
1981-07-01 03:59:60 1981-07-01 03:59:59
drop table t1; drop table t1;
create table t1 (ts timestamp); create table t1 (ts timestamp);
set time_zone='UTC'; set time_zone='UTC';
......
...@@ -17,6 +17,9 @@ insert into t1 values ...@@ -17,6 +17,9 @@ insert into t1 values
insert into t1 values insert into t1 values
(unix_timestamp('1981-07-01 03:59:59'),'1981-07-01 03:59:59'), (unix_timestamp('1981-07-01 03:59:59'),'1981-07-01 03:59:59'),
(unix_timestamp('1981-07-01 04:00:00'),'1981-07-01 04:00:00'); (unix_timestamp('1981-07-01 04:00:00'),'1981-07-01 04:00:00');
insert into t1 values
(unix_timestamp('2009-01-01 02:59:59'),'2009-01-01 02:59:59'),
(unix_timestamp('2009-01-01 03:00:00'),'2009-01-01 03:00:00');
select i, from_unixtime(i), c from t1; select i, from_unixtime(i), c from t1;
i from_unixtime(i) c i from_unixtime(i) c
1072904422 2004-01-01 00:00:00 2004-01-01 00:00:00 1072904422 2004-01-01 00:00:00 2004-01-01 00:00:00
...@@ -31,6 +34,8 @@ i from_unixtime(i) c ...@@ -31,6 +34,8 @@ i from_unixtime(i) c
1099180821 2004-10-31 02:59:59 2004-10-31 02:59:59 1099180821 2004-10-31 02:59:59 2004-10-31 02:59:59
362793608 1981-07-01 03:59:59 1981-07-01 03:59:59 362793608 1981-07-01 03:59:59 1981-07-01 03:59:59
362793610 1981-07-01 04:00:00 1981-07-01 04:00:00 362793610 1981-07-01 04:00:00 1981-07-01 04:00:00
1230768022 2009-01-01 02:59:59 2009-01-01 02:59:59
1230768024 2009-01-01 03:00:00 2009-01-01 03:00:00
drop table t1; drop table t1;
create table t1 (ts timestamp); create table t1 (ts timestamp);
insert into t1 values (19730101235900), (20040101235900); insert into t1 values (19730101235900), (20040101235900);
...@@ -39,3 +44,6 @@ ts ...@@ -39,3 +44,6 @@ ts
1973-01-01 23:59:00 1973-01-01 23:59:00
2004-01-01 23:59:00 2004-01-01 23:59:00
drop table t1; drop table t1;
SELECT FROM_UNIXTIME(1230768022), FROM_UNIXTIME(1230768023), FROM_UNIXTIME(1230768024);
FROM_UNIXTIME(1230768022) FROM_UNIXTIME(1230768023) FROM_UNIXTIME(1230768024)
2009-01-01 02:59:59 2009-01-01 02:59:59 2009-01-01 03:00:00
...@@ -45,6 +45,10 @@ insert into t1 values ...@@ -45,6 +45,10 @@ insert into t1 values
(unix_timestamp('1981-07-01 03:59:59'),'1981-07-01 03:59:59'), (unix_timestamp('1981-07-01 03:59:59'),'1981-07-01 03:59:59'),
(unix_timestamp('1981-07-01 04:00:00'),'1981-07-01 04:00:00'); (unix_timestamp('1981-07-01 04:00:00'),'1981-07-01 04:00:00');
insert into t1 values
(unix_timestamp('2009-01-01 02:59:59'),'2009-01-01 02:59:59'),
(unix_timestamp('2009-01-01 03:00:00'),'2009-01-01 03:00:00');
select i, from_unixtime(i), c from t1; select i, from_unixtime(i), c from t1;
drop table t1; drop table t1;
...@@ -58,4 +62,12 @@ insert into t1 values (19730101235900), (20040101235900); ...@@ -58,4 +62,12 @@ insert into t1 values (19730101235900), (20040101235900);
select * from t1; select * from t1;
drop table t1; drop table t1;
#
# Test Bug #39920: MySQL cannot deal with Leap Second expression in string
# literal
#
# 2009-01-01 02:59:59, 2009-01-01 02:59:60 and 2009-01-01 03:00:00
SELECT FROM_UNIXTIME(1230768022), FROM_UNIXTIME(1230768023), FROM_UNIXTIME(1230768024);
# End of 4.1 tests # End of 4.1 tests
...@@ -1073,6 +1073,7 @@ Time_zone_system::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const ...@@ -1073,6 +1073,7 @@ Time_zone_system::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
localtime_r(&tmp_t, &tmp_tm); localtime_r(&tmp_t, &tmp_tm);
localtime_to_TIME(tmp, &tmp_tm); localtime_to_TIME(tmp, &tmp_tm);
tmp->time_type= MYSQL_TIMESTAMP_DATETIME; tmp->time_type= MYSQL_TIMESTAMP_DATETIME;
adjust_leap_second(tmp);
} }
...@@ -1157,6 +1158,7 @@ Time_zone_utc::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const ...@@ -1157,6 +1158,7 @@ Time_zone_utc::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
gmtime_r(&tmp_t, &tmp_tm); gmtime_r(&tmp_t, &tmp_tm);
localtime_to_TIME(tmp, &tmp_tm); localtime_to_TIME(tmp, &tmp_tm);
tmp->time_type= MYSQL_TIMESTAMP_DATETIME; tmp->time_type= MYSQL_TIMESTAMP_DATETIME;
adjust_leap_second(tmp);
} }
...@@ -1260,6 +1262,7 @@ void ...@@ -1260,6 +1262,7 @@ void
Time_zone_db::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const Time_zone_db::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
{ {
::gmt_sec_to_TIME(tmp, t, tz_info); ::gmt_sec_to_TIME(tmp, t, tz_info);
adjust_leap_second(tmp);
} }
...@@ -2373,6 +2376,25 @@ Time_zone *my_tz_find_with_opening_tz_tables(THD *thd, const String *name) ...@@ -2373,6 +2376,25 @@ Time_zone *my_tz_find_with_opening_tz_tables(THD *thd, const String *name)
DBUG_RETURN(tz); DBUG_RETURN(tz);
} }
/**
Convert leap seconds into non-leap
This function will convert the leap seconds added by the OS to
non-leap seconds, e.g. 23:59:59, 23:59:60 -> 23:59:59, 00:00:01 ...
This check is not checking for years on purpose : although it's not a
complete check this way it doesn't require looking (and having installed)
the leap seconds table.
@param[in,out] broken down time structure as filled in by the OS
*/
void Time_zone::adjust_leap_second(MYSQL_TIME *t)
{
if (t->second == 60 || t->second == 61)
t->second= 59;
}
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */ #endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
......
...@@ -55,6 +55,9 @@ public: ...@@ -55,6 +55,9 @@ public:
allocated on MEM_ROOT and should not require destruction. allocated on MEM_ROOT and should not require destruction.
*/ */
virtual ~Time_zone() {}; virtual ~Time_zone() {};
protected:
static inline void adjust_leap_second(MYSQL_TIME *t);
}; };
extern Time_zone * my_tz_UTC; extern Time_zone * my_tz_UTC;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment