summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/timezone.result6
-rw-r--r--mysql-test/t/timezone.test7
-rw-r--r--sql/field.cc14
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/time.cc19
5 files changed, 32 insertions, 17 deletions
diff --git a/mysql-test/r/timezone.result b/mysql-test/r/timezone.result
index 20706408075..15f0d4121c7 100644
--- a/mysql-test/r/timezone.result
+++ b/mysql-test/r/timezone.result
@@ -32,3 +32,9 @@ ts from_unixtime(ts)
1048989599 2003-03-30 03:59:59
1048989601 2003-03-30 04:00:01
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
diff --git a/mysql-test/t/timezone.test b/mysql-test/t/timezone.test
index ab732c11a34..ba65eb72fe6 100644
--- a/mysql-test/t/timezone.test
+++ b/mysql-test/t/timezone.test
@@ -38,3 +38,10 @@ INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 04:00:01'));
SELECT ts,from_unixtime(ts) FROM t1;
DROP TABLE t1;
+#
+# Test for fix for Bug#2523
+#
+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');
diff --git a/sql/field.cc b/sql/field.cc
index 687c22bb69b..ac3ebb4bfc7 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2583,22 +2583,18 @@ static longlong fix_datetime(longlong nr, TIME *time_res)
void Field_timestamp::store(longlong nr)
{
TIME l_time;
- time_t timestamp;
+ time_t timestamp= 0;
if ((nr= fix_datetime(nr, &l_time)))
{
long not_used;
- if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR-1)
- {
+ timestamp= my_gmt_sec(&l_time, &not_used);
+
+ if (!timestamp)
current_thd->cuted_fields++;
- timestamp=0;
- }
- else
- timestamp=my_gmt_sec(&l_time, &not_used);
}
- else
- timestamp=0;
+
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index acb7005c26c..46f7ece8641 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -116,6 +116,9 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
/* Time handling defaults */
#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_MIN_VALUE 1
#define PRECISION_FOR_DOUBLE 53
#define PRECISION_FOR_FLOAT 24
diff --git a/sql/time.cc b/sql/time.cc
index 5dc229b1d88..0363d764100 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -63,6 +63,9 @@ long my_gmt_sec(TIME *t, long *my_timezone)
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;
@@ -125,8 +128,10 @@ long my_gmt_sec(TIME *t, long *my_timezone)
tmp-=t->minute*60 + t->second; // Move to previous hour
}
*my_timezone= current_timezone;
- if (tmp < 0 && t->year <= 1900+YY_PART_YEAR)
+
+ if (tmp < TIMESTAMP_MIN_VALUE || tmp > TIMESTAMP_MAX_VALUE)
tmp= 0;
+
return (long) tmp;
} /* my_gmt_sec */
@@ -444,15 +449,13 @@ time_t str_to_timestamp(const char *str,uint length)
{
TIME l_time;
long not_used;
+ time_t timestamp= 0;
- if (str_to_TIME(str,length,&l_time,0) == TIMESTAMP_NONE)
- return(0);
- if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR-1)
- {
+ if (str_to_TIME(str,length,&l_time,0) != TIMESTAMP_NONE &&
+ !(timestamp= my_gmt_sec(&l_time, &not_used)))
current_thd->cuted_fields++;
- return(0);
- }
- return(my_gmt_sec(&l_time, &not_used));
+
+ return timestamp;
}