summaryrefslogtreecommitdiff
path: root/sql/tztime.cc
diff options
context:
space:
mode:
authorunknown <petr/cps@mysql.com/owlet.local>2006-11-01 17:35:35 +0300
committerunknown <petr/cps@mysql.com/owlet.local>2006-11-01 17:35:35 +0300
commitb2c40c169869f7df93342b434b84af4fb26acbe2 (patch)
tree943fb5e51a9978101520019d70d4771a9085dfab /sql/tztime.cc
parent8db4dc3f91dfbe03181e63ed45bdf35a5d65aeb0 (diff)
parent8a7bc052885494b83fed51d785d9fc4b1cfa9df1 (diff)
downloadmariadb-git-b2c40c169869f7df93342b434b84af4fb26acbe2.tar.gz
Merge mysql.com:/home/cps/mysql/trees/4.1-runtime-bug9191
into mysql.com:/home/cps/mysql/trees/5.0-runtime-bug9191 configure.in: Auto merged include/my_time.h: Auto merged mysql-test/r/func_time.result: Auto merged mysql-test/r/timezone2.result: Auto merged mysql-test/t/func_time.test: Auto merged mysql-test/t/timezone2.test: Auto merged sql/mysql_priv.h: Auto merged sql/time.cc: Auto merged BitKeeper/deleted/.del-acinclude.m4~f4ab416bac5003: Auto merged sql-common/my_time.c: manual merge sql/item_timefunc.cc: manual merge sql/tztime.cc: manual merge
Diffstat (limited to 'sql/tztime.cc')
-rw-r--r--sql/tztime.cc77
1 files changed, 69 insertions, 8 deletions
diff --git a/sql/tztime.cc b/sql/tztime.cc
index d12aef47b40..15cd862f4b9 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -886,8 +886,14 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp,
my_time_t local_t;
uint saved_seconds;
uint i;
+ int shift= 0;
+
DBUG_ENTER("TIME_to_gmt_sec");
+ if (!validate_timestamp_range(t))
+ return 0;
+
+
/* We need this for correct leap seconds handling */
if (t->second < SECS_PER_MIN)
saved_seconds= 0;
@@ -895,11 +901,29 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp,
saved_seconds= t->second;
/*
- NOTE If we want to convert full my_time_t range without MySQL
- restrictions we should catch overflow here somehow.
+ NOTE: to convert full my_time_t range we do a shift of the
+ boundary dates here to avoid overflow of my_time_t.
+ We use alike approach in my_system_gmt_sec().
+
+ However in that function we also have to take into account
+ overflow near 0 on some platforms. That's because my_system_gmt_sec
+ uses localtime_r(), which doesn't work with negative values correctly
+ on platforms with unsigned time_t (QNX). Here we don't use localtime()
+ => we negative values of local_t are ok.
*/
- local_t= sec_since_epoch(t->year, t->month, t->day,
+ if ((t->year == TIMESTAMP_MAX_YEAR) && (t->month == 1) && t->day > 4)
+ {
+ /*
+ We will pass (t->day - shift) to sec_since_epoch(), and
+ want this value to be a positive number, so we shift
+ only dates > 4.01.2038 (to avoid owerflow).
+ */
+ shift= 2;
+ }
+
+
+ local_t= sec_since_epoch(t->year, t->month, (t->day - shift),
t->hour, t->minute,
saved_seconds ? 0 : t->second);
@@ -918,6 +942,22 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp,
/* binary search for our range */
i= find_time_range(local_t, sp->revts, sp->revcnt);
+ /*
+ As there are no offset switches at the end of TIMESTAMP range,
+ we could simply check for overflow here (and don't need to bother
+ about DST gaps etc)
+ */
+ if (shift)
+ {
+ if (local_t > (TIMESTAMP_MAX_VALUE - shift*86400L +
+ sp->revtis[i].rt_offset - saved_seconds))
+ {
+ DBUG_RETURN(0); /* my_time_t overflow */
+ }
+ else
+ local_t+= shift*86400L;
+ }
+
if (sp->revtis[i].rt_type)
{
/*
@@ -927,10 +967,16 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp,
beginning of the gap.
*/
*in_dst_time_gap= 1;
- DBUG_RETURN(sp->revts[i] - sp->revtis[i].rt_offset + saved_seconds);
+ local_t= sp->revts[i] - sp->revtis[i].rt_offset + saved_seconds;
}
else
- DBUG_RETURN(local_t - sp->revtis[i].rt_offset + saved_seconds);
+ local_t= local_t - sp->revtis[i].rt_offset + saved_seconds;
+
+ /* check for TIMESTAMP_MAX_VALUE was already done above */
+ if (local_t < TIMESTAMP_MIN_VALUE)
+ local_t= 0;
+
+ DBUG_RETURN(local_t);
}
@@ -1296,9 +1342,24 @@ Time_zone_offset::Time_zone_offset(long tz_offset_arg):
my_time_t
Time_zone_offset::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
{
- return sec_since_epoch(t->year, t->month, t->day,
- t->hour, t->minute, t->second) -
- offset;
+ my_time_t local_t;
+
+ /*
+ Check timestamp range.we have to do this as calling function relies on
+ us to make all validation checks here.
+ */
+ if (!validate_timestamp_range(t))
+ return 0;
+
+ local_t= sec_since_epoch(t->year, t->month, t->day,
+ t->hour, t->minute, t->second) -
+ offset;
+
+ if (local_t >= TIMESTAMP_MIN_VALUE && local_t <= TIMESTAMP_MAX_VALUE)
+ return local_t;
+
+ /* range error*/
+ return 0;
}