Below is the list of changes that have just been committed into a local
4.0 repository of cps. When cps does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2006-08-03 15:35:01+04:00, petr@stripped +6 -0
Fix Bug #9191 from_unixtime(power(2,31)-1) now epoch instead of 2038-01-19
(4.0 version, recommited to fix a typo in a test file)
mysql-test/r/func_time.result@stripped, 2006-08-03 15:35:00+04:00, petr@stripped +11 -2
Update result file
mysql-test/r/timezone.result@stripped, 2006-08-03 15:35:00+04:00, petr@stripped +4 -4
Update result file
mysql-test/t/func_time.test@stripped, 2006-08-03 15:35:00+04:00, petr@stripped +20 -6
add test for the bug
mysql-test/t/timezone.test@stripped, 2006-08-03 15:35:00+04:00, petr@stripped +3 -3
change test to check (updated) boundary dates
sql/mysql_priv.h@stripped, 2006-08-03 15:35:00+04:00, petr@stripped +1 -1
change TIMESTAMP_MAX_VALUE to reflect the bugfix:
now all timestamp values, which from_unixtime
representation <= then INT_MAX32 are valid
sql/time.cc@stripped, 2006-08-03 15:35:00+04:00, petr@stripped +53 -11
Step back from a boudary dates to avoid overflows
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: petr
# Host: owlet.
# Root: /home/cps/mysql/trees/mysql-4.0-bug
--- 1.239/sql/mysql_priv.h 2006-08-03 15:35:04 +04:00
+++ 1.240/sql/mysql_priv.h 2006-08-03 15:35:04 +04:00
@@ -118,7 +118,7 @@
#define TIMESTAMP_MAX_YEAR 2038
#define YY_PART_YEAR 70
#define TIMESTAMP_MIN_YEAR (1900 + YY_PART_YEAR - 1)
-#define TIMESTAMP_MAX_VALUE 2145916799
+#define TIMESTAMP_MAX_VALUE INT_MAX32
#define TIMESTAMP_MIN_VALUE 1
#define PRECISION_FOR_DOUBLE 53
#define PRECISION_FOR_FLOAT 24
--- 1.30/sql/time.cc 2006-08-03 15:35:04 +04:00
+++ 1.31/sql/time.cc 2006-08-03 15:35:04 +04:00
@@ -59,13 +59,14 @@
long my_gmt_sec(TIME *t, long *my_timezone)
{
uint loop;
- time_t tmp;
+ time_t tmp= 0;
+ int shift= 0;
struct tm *l_time,tm_tmp;
long diff, current_timezone;
if (t->year > TIMESTAMP_MAX_YEAR || t->year < TIMESTAMP_MIN_YEAR)
return 0;
-
+
if (t->hour >= 24)
{ /* Fix for time-loop */
t->day+=t->hour/24;
@@ -85,15 +86,52 @@
Note: this code assumes that our time_t estimation is not too far away
from real value (we assume that localtime_r(tmp) will return something
within 24 hrs from t) which is probably true for all current time zones.
+
+ Note2: For the dates, which have time_t representation close to
+ MAX_INT32 (efficient time_t limit for supported platforms), we should
+ do a small trick to avoid overflow. That is, convert the date, which is
+ two days earlier, and then add this day to the final value.
+
+ The same trick is done for the values close to 0 in time_t
+ representation. We have to deal with it since at least one of
+ the platforms we support (QNX) has unsigned time_t.
+
+ We are safe here as (1) we check that the date is not too far away
+ from the boundaries, and (2) there are no DST switches in December
+ and January.
*/
- tmp=(time_t) (((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) -
- (long) days_at_timestart)*86400L + (long) t->hour*3600L +
- (long) (t->minute*60 + t->second)) + (time_t) my_time_zone -
- 3600);
+ if ((t->year == TIMESTAMP_MAX_YEAR) && (t->month == 1))
+ if ((t->day > 2) && t->day <= 19)
+ shift= 2;
+ /* 2038, 19 of Jan is the max possible date within time_t range */
+ else
+ goto end;
+
+ if ((t->year == TIMESTAMP_MIN_YEAR) && (t->month == 12))
+ if ((t->day >= 31) && t->day <= 19)
+ shift= -2;
+ /* 1969, 31 of Dec is min possible date within time_t range */
+ else
+ goto end;
+
+ tmp= (time_t) (((calc_daynr((uint) t->year, (uint) t->month,
+ (uint) (t->day - shift)) -
+ (long) days_at_timestart)*86400L + (long) t->hour*3600L +
+ (long) (t->minute*60 + t->second)) + (time_t) my_time_zone -
+ 3600);
+
current_timezone= my_time_zone;
+ if ((uint) tmp > TIMESTAMP_MAX_VALUE)
+ {
+ tmp= 0;
+ goto end;
+ }
+
localtime_r(&tmp,&tm_tmp);
+
l_time=&tm_tmp;
+
for (loop=0;
loop < 2 &&
(t->hour != (uint) l_time->tm_hour ||
@@ -102,7 +140,7 @@
loop++)
{ /* One check should be enough ? */
/* Get difference in days */
- int days= t->day - l_time->tm_mday;
+ int days= (t->day - shift) - l_time->tm_mday;
if (days < -1)
days= 1; // Month has wrapped
else if (days > 1)
@@ -141,10 +179,14 @@
tmp-=t->minute*60 + t->second; // Move to previous hour
}
*my_timezone= current_timezone;
-
- if (tmp < TIMESTAMP_MIN_VALUE || tmp > TIMESTAMP_MAX_VALUE)
+
+ /* shift back, if we were dealing with boundary dates */
+ tmp+= shift*86400L;
+
+ if (tmp < TIMESTAMP_MIN_VALUE || (tmp > TIMESTAMP_MAX_VALUE))
tmp= 0;
-
+
+end:
return (long) tmp;
} /* my_gmt_sec */
@@ -467,7 +509,7 @@
if (str_to_TIME(str,length,&l_time,0) != TIMESTAMP_NONE &&
!(timestamp= my_gmt_sec(&l_time, ¬_used)))
current_thd->cuted_fields++;
-
+
return timestamp;
}
--- 1.24/mysql-test/r/func_time.result 2006-08-03 15:35:04 +04:00
+++ 1.25/mysql-test/r/func_time.result 2006-08-03 15:35:04 +04:00
@@ -473,9 +473,18 @@
select from_unixtime(-1);
from_unixtime(-1)
NULL
-select from_unixtime(2145916800);
-from_unixtime(2145916800)
+select from_unixtime(2147483647);
+from_unixtime(2147483647)
+2038-01-19 06:14:07
+select from_unixtime(2147483648);
+from_unixtime(2147483648)
NULL
select from_unixtime(0);
from_unixtime(0)
1970-01-01 03:00:00
+select unix_timestamp(from_unixtime(2147483647));
+unix_timestamp(from_unixtime(2147483647))
+2147483647
+select unix_timestamp(from_unixtime(2147483648));
+unix_timestamp(from_unixtime(2147483648))
+NULL
--- 1.21/mysql-test/t/func_time.test 2006-08-03 15:35:04 +04:00
+++ 1.22/mysql-test/t/func_time.test 2006-08-03 15:35:04 +04:00
@@ -227,12 +227,26 @@
select unix_timestamp('1969-12-01 19:00:01');
#
-# Test for bug #6439 "unix_timestamp() function returns wrong datetime
-# values for too big argument" and bug #7515 "from_unixtime(0) now
-# returns NULL instead of the epoch". unix_timestamp() should return error
-# for too big or negative argument. It should return Epoch value for zero
-# argument since it seems that many user's rely on this fact.
+# Tests for bug #6439 "unix_timestamp() function returns wrong datetime
+# values for too big argument", bug #7515 "from_unixtime(0) now
+# returns NULL instead of the epoch" and bug #9191
+# "from_unixtime(power(2,31)-1) now epoch instead of 2038-01-19.
+# unix_timestamp() should return error for too big or negative argument.
+# It should return Epoch value for zero argument since it seems that many
+# user's rely on this fact, from_unixtime() should work with values
+# up to INT_MAX32-1 because of the same reason.
#
select from_unixtime(-1);
-select from_unixtime(2145916800);
+# the following is in fact check for argument equal to 2^31-1 and 2^31
+select from_unixtime(2147483647);
+select from_unixtime(2147483648);
select from_unixtime(0);
+
+#
+# Some more tests for bug #9191 "from_unixtime(power(2,31)-1) now epoch
+# instead of 2038-01-19. Here we test that from_unixtime and unix_timestamp
+# are consistent, when working with boundary dates
+#
+select unix_timestamp(from_unixtime(2147483647));
+select unix_timestamp(from_unixtime(2147483648));
+
--- 1.4/mysql-test/r/timezone.result 2006-08-03 15:35:04 +04:00
+++ 1.5/mysql-test/r/timezone.result 2006-08-03 15:35:04 +04:00
@@ -34,7 +34,7 @@
DROP TABLE t1;
select unix_timestamp('1970-01-01 01:00:00'),
unix_timestamp('1970-01-01 01:00:01'),
-unix_timestamp('2038-01-01 00:59:59'),
-unix_timestamp('2038-01-01 01:00:00');
-unix_timestamp('1970-01-01 01:00:00') unix_timestamp('1970-01-01
01:00:01') unix_timestamp('2038-01-01 00:59:59') unix_timestamp('2038-01-01 01:00:00')
-0 1 2145916799 0
+unix_timestamp('2038-01-19 04:14:07'),
+unix_timestamp('2038-01-19 04:14:08');
+unix_timestamp('1970-01-01 01:00:00') unix_timestamp('1970-01-01
01:00:01') unix_timestamp('2038-01-19 04:14:07') unix_timestamp('2038-01-19 04:14:08')
+0 1 2147483647 0
--- 1.6/mysql-test/t/timezone.test 2006-08-03 15:35:04 +04:00
+++ 1.7/mysql-test/t/timezone.test 2006-08-03 15:35:04 +04:00
@@ -41,9 +41,9 @@
DROP TABLE t1;
#
-# Test for fix for Bug#2523
+# Test fix for Bug#2523. Check that boundary dates are processed correctly
#
select unix_timestamp('1970-01-01 01:00:00'),
unix_timestamp('1970-01-01 01:00:01'),
- unix_timestamp('2038-01-01 00:59:59'),
- unix_timestamp('2038-01-01 01:00:00');
+ unix_timestamp('2038-01-19 04:14:07'),
+ unix_timestamp('2038-01-19 04:14:08');
| Thread |
|---|
| • bk commit into 4.0 tree (petr:1.2193) BUG#9191 | Petr Chardin | 3 Aug |