mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 12:32:27 +01:00
Merge pchardin@bk-internal.mysql.com:/home/bk/mysql-5.1-runtime
into outpost.site:/home/cps/mysql/trees/5.1-runtime-bug9191 configure.in: Auto merged mysql-test/mysql-test-run.pl: Auto merged sql/item_timefunc.cc: Auto merged sql/mysql_priv.h: Auto merged
This commit is contained in:
commit
50ba1a09c1
17 changed files with 365 additions and 70 deletions
|
@ -1696,6 +1696,13 @@ then
|
||||||
AC_MSG_ERROR("MySQL needs a off_t type.")
|
AC_MSG_ERROR("MySQL needs a off_t type.")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl check if time_t is unsigned
|
||||||
|
dnl
|
||||||
|
|
||||||
|
MYSQL_CHECK_TIME_T
|
||||||
|
|
||||||
|
|
||||||
# do we need #pragma interface/#pragma implementation ?
|
# do we need #pragma interface/#pragma implementation ?
|
||||||
# yes if it's gcc 2.x, and not icc pretending to be gcc, and not cygwin
|
# yes if it's gcc 2.x, and not icc pretending to be gcc, and not cygwin
|
||||||
AC_MSG_CHECKING(the need for @%:@pragma interface/implementation)
|
AC_MSG_CHECKING(the need for @%:@pragma interface/implementation)
|
||||||
|
|
|
@ -43,6 +43,12 @@ typedef long my_time_t;
|
||||||
#define MY_TIME_T_MAX LONG_MAX
|
#define MY_TIME_T_MAX LONG_MAX
|
||||||
#define MY_TIME_T_MIN LONG_MIN
|
#define MY_TIME_T_MIN LONG_MIN
|
||||||
|
|
||||||
|
/* Time handling defaults */
|
||||||
|
#define TIMESTAMP_MAX_YEAR 2038
|
||||||
|
#define TIMESTAMP_MIN_YEAR (1900 + YY_PART_YEAR - 1)
|
||||||
|
#define TIMESTAMP_MAX_VALUE INT_MAX32
|
||||||
|
#define TIMESTAMP_MIN_VALUE 1
|
||||||
|
|
||||||
/* two-digit years < this are 20..; >= this are 19.. */
|
/* two-digit years < this are 20..; >= this are 19.. */
|
||||||
#define YY_PART_YEAR 70
|
#define YY_PART_YEAR 70
|
||||||
/* apply above magic to years < this */
|
/* apply above magic to years < this */
|
||||||
|
@ -76,6 +82,30 @@ uint calc_days_in_year(uint year);
|
||||||
|
|
||||||
void init_time(void);
|
void init_time(void);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function to check sanity of a TIMESTAMP value
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Check if a given MYSQL_TIME value fits in TIMESTAMP range.
|
||||||
|
This function doesn't make precise check, but rather a rough
|
||||||
|
estimate.
|
||||||
|
|
||||||
|
RETURN VALUES
|
||||||
|
FALSE The value seems sane
|
||||||
|
TRUE The MYSQL_TIME value is definitely out of range
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline bool validate_timestamp_range(const MYSQL_TIME *t)
|
||||||
|
{
|
||||||
|
if ((t->year > TIMESTAMP_MAX_YEAR || t->year < TIMESTAMP_MIN_YEAR) ||
|
||||||
|
(t->year == TIMESTAMP_MAX_YEAR && (t->month > 1 || t->day > 19)) ||
|
||||||
|
(t->year == TIMESTAMP_MIN_YEAR && (t->month < 12 || t->day < 31)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
my_time_t
|
my_time_t
|
||||||
my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone,
|
my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone,
|
||||||
my_bool *in_dst_time_gap);
|
my_bool *in_dst_time_gap);
|
||||||
|
|
|
@ -3621,6 +3621,14 @@ sub run_testcase_start_servers($) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set the timezone, in the case it was specified in the test
|
||||||
|
# We need to do this before the server is started, as mysqld
|
||||||
|
# uses this information at startup
|
||||||
|
#
|
||||||
|
|
||||||
|
$ENV{'TZ'}= $tinfo->{'timezone'};
|
||||||
|
|
||||||
if ( $tinfo->{'component_id'} eq 'mysqld' )
|
if ( $tinfo->{'component_id'} eq 'mysqld' )
|
||||||
{
|
{
|
||||||
if ( ! $opt_skip_ndbcluster and
|
if ( ! $opt_skip_ndbcluster and
|
||||||
|
@ -3985,7 +3993,6 @@ sub run_mysqltest ($) {
|
||||||
# -------------------------------------------------------
|
# -------------------------------------------------------
|
||||||
# Init variables that change for each testcase
|
# Init variables that change for each testcase
|
||||||
# -------------------------------------------------------
|
# -------------------------------------------------------
|
||||||
$ENV{'TZ'}= $tinfo->{'timezone'};
|
|
||||||
|
|
||||||
my $res = mtr_run_test($exe,$args,"","",$path_timefile,"");
|
my $res = mtr_run_test($exe,$args,"","",$path_timefile,"");
|
||||||
|
|
||||||
|
|
|
@ -548,12 +548,48 @@ unix_timestamp('1969-12-01 19:00:01')
|
||||||
select from_unixtime(-1);
|
select from_unixtime(-1);
|
||||||
from_unixtime(-1)
|
from_unixtime(-1)
|
||||||
NULL
|
NULL
|
||||||
select from_unixtime(2145916800);
|
select from_unixtime(2147483647);
|
||||||
from_unixtime(2145916800)
|
from_unixtime(2147483647)
|
||||||
|
2038-01-19 06:14:07
|
||||||
|
select from_unixtime(2147483648);
|
||||||
|
from_unixtime(2147483648)
|
||||||
NULL
|
NULL
|
||||||
select from_unixtime(0);
|
select from_unixtime(0);
|
||||||
from_unixtime(0)
|
from_unixtime(0)
|
||||||
1970-01-01 03:00:00
|
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
|
||||||
|
select unix_timestamp('2039-01-20 01:00:00');
|
||||||
|
unix_timestamp('2039-01-20 01:00:00')
|
||||||
|
0
|
||||||
|
select unix_timestamp('1968-01-20 01:00:00');
|
||||||
|
unix_timestamp('1968-01-20 01:00:00')
|
||||||
|
0
|
||||||
|
select unix_timestamp('2038-02-10 01:00:00');
|
||||||
|
unix_timestamp('2038-02-10 01:00:00')
|
||||||
|
0
|
||||||
|
select unix_timestamp('1969-11-20 01:00:00');
|
||||||
|
unix_timestamp('1969-11-20 01:00:00')
|
||||||
|
0
|
||||||
|
select unix_timestamp('2038-01-20 01:00:00');
|
||||||
|
unix_timestamp('2038-01-20 01:00:00')
|
||||||
|
0
|
||||||
|
select unix_timestamp('1969-12-30 01:00:00');
|
||||||
|
unix_timestamp('1969-12-30 01:00:00')
|
||||||
|
0
|
||||||
|
select unix_timestamp('2038-01-17 12:00:00');
|
||||||
|
unix_timestamp('2038-01-17 12:00:00')
|
||||||
|
2147331600
|
||||||
|
select unix_timestamp('1970-01-01 03:00:01');
|
||||||
|
unix_timestamp('1970-01-01 03:00:01')
|
||||||
|
1
|
||||||
|
select unix_timestamp('2038-01-19 07:14:07');
|
||||||
|
unix_timestamp('2038-01-19 07:14:07')
|
||||||
|
0
|
||||||
CREATE TABLE t1 (datetime datetime, timestamp timestamp, date date, time time);
|
CREATE TABLE t1 (datetime datetime, timestamp timestamp, date date, time time);
|
||||||
INSERT INTO t1 values ("2001-01-02 03:04:05", "2002-01-02 03:04:05", "2003-01-02", "06:07:08");
|
INSERT INTO t1 values ("2001-01-02 03:04:05", "2002-01-02 03:04:05", "2003-01-02", "06:07:08");
|
||||||
SELECT * from t1;
|
SELECT * from t1;
|
||||||
|
|
|
@ -41,7 +41,7 @@ Warning 1299 Invalid TIMESTAMP value in column 'ts' at row 2
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
select unix_timestamp('1970-01-01 01:00:00'),
|
select unix_timestamp('1970-01-01 01:00:00'),
|
||||||
unix_timestamp('1970-01-01 01:00:01'),
|
unix_timestamp('1970-01-01 01:00:01'),
|
||||||
unix_timestamp('2038-01-01 00:59:59'),
|
unix_timestamp('2038-01-19 04:14:07'),
|
||||||
unix_timestamp('2038-01-01 01:00:00');
|
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-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-19 04:14:07') unix_timestamp('2038-01-19 04:14:08')
|
||||||
0 1 2145916799 0
|
0 1 2147483647 0
|
||||||
|
|
|
@ -116,7 +116,7 @@ create table t1 (ts timestamp);
|
||||||
set time_zone='UTC';
|
set time_zone='UTC';
|
||||||
insert into t1 values ('0000-00-00 00:00:00'),('1969-12-31 23:59:59'),
|
insert into t1 values ('0000-00-00 00:00:00'),('1969-12-31 23:59:59'),
|
||||||
('1970-01-01 00:00:00'),('1970-01-01 00:00:01'),
|
('1970-01-01 00:00:00'),('1970-01-01 00:00:01'),
|
||||||
('2037-12-31 23:59:59'),('2038-01-01 00:00:00');
|
('2038-01-19 03:14:07'),('2038-01-19 03:14:08');
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1264 Out of range value for column 'ts' at row 2
|
Warning 1264 Out of range value for column 'ts' at row 2
|
||||||
Warning 1264 Out of range value for column 'ts' at row 3
|
Warning 1264 Out of range value for column 'ts' at row 3
|
||||||
|
@ -127,13 +127,13 @@ ts
|
||||||
0000-00-00 00:00:00
|
0000-00-00 00:00:00
|
||||||
0000-00-00 00:00:00
|
0000-00-00 00:00:00
|
||||||
1970-01-01 00:00:01
|
1970-01-01 00:00:01
|
||||||
2037-12-31 23:59:59
|
2038-01-19 03:14:07
|
||||||
0000-00-00 00:00:00
|
0000-00-00 00:00:00
|
||||||
truncate table t1;
|
truncate table t1;
|
||||||
set time_zone='MET';
|
set time_zone='MET';
|
||||||
insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 00:30:00'),
|
insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 00:30:00'),
|
||||||
('1970-01-01 01:00:00'),('1970-01-01 01:00:01'),
|
('1970-01-01 01:00:00'),('1970-01-01 01:00:01'),
|
||||||
('2038-01-01 00:59:59'),('2038-01-01 01:00:00');
|
('2038-01-19 04:14:07'),('2038-01-19 04:14:08');
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1264 Out of range value for column 'ts' at row 2
|
Warning 1264 Out of range value for column 'ts' at row 2
|
||||||
Warning 1264 Out of range value for column 'ts' at row 3
|
Warning 1264 Out of range value for column 'ts' at row 3
|
||||||
|
@ -144,13 +144,13 @@ ts
|
||||||
0000-00-00 00:00:00
|
0000-00-00 00:00:00
|
||||||
0000-00-00 00:00:00
|
0000-00-00 00:00:00
|
||||||
1970-01-01 01:00:01
|
1970-01-01 01:00:01
|
||||||
2038-01-01 00:59:59
|
2038-01-19 04:14:07
|
||||||
0000-00-00 00:00:00
|
0000-00-00 00:00:00
|
||||||
truncate table t1;
|
truncate table t1;
|
||||||
set time_zone='+01:30';
|
set time_zone='+01:30';
|
||||||
insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 01:00:00'),
|
insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 01:00:00'),
|
||||||
('1970-01-01 01:30:00'),('1970-01-01 01:30:01'),
|
('1970-01-01 01:30:00'),('1970-01-01 01:30:01'),
|
||||||
('2038-01-01 01:29:59'),('2038-01-01 01:30:00');
|
('2038-01-19 04:44:07'),('2038-01-19 04:44:08');
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1264 Out of range value for column 'ts' at row 2
|
Warning 1264 Out of range value for column 'ts' at row 2
|
||||||
Warning 1264 Out of range value for column 'ts' at row 3
|
Warning 1264 Out of range value for column 'ts' at row 3
|
||||||
|
@ -161,7 +161,7 @@ ts
|
||||||
0000-00-00 00:00:00
|
0000-00-00 00:00:00
|
||||||
0000-00-00 00:00:00
|
0000-00-00 00:00:00
|
||||||
1970-01-01 01:30:01
|
1970-01-01 01:30:01
|
||||||
2038-01-01 01:29:59
|
2038-01-19 04:44:07
|
||||||
0000-00-00 00:00:00
|
0000-00-00 00:00:00
|
||||||
drop table t1;
|
drop table t1;
|
||||||
show variables like 'time_zone';
|
show variables like 'time_zone';
|
||||||
|
@ -223,12 +223,12 @@ convert_tz('2003-10-26 02:59:59', 'MET', 'UTC')
|
||||||
select convert_tz('2003-10-26 04:00:00', 'MET', 'UTC');
|
select convert_tz('2003-10-26 04:00:00', 'MET', 'UTC');
|
||||||
convert_tz('2003-10-26 04:00:00', 'MET', 'UTC')
|
convert_tz('2003-10-26 04:00:00', 'MET', 'UTC')
|
||||||
2003-10-26 03:00:00
|
2003-10-26 03:00:00
|
||||||
select convert_tz('2038-01-01 00:59:59', 'MET', 'UTC');
|
select convert_tz('2038-01-19 04:14:07', 'MET', 'UTC');
|
||||||
convert_tz('2038-01-01 00:59:59', 'MET', 'UTC')
|
convert_tz('2038-01-19 04:14:07', 'MET', 'UTC')
|
||||||
2037-12-31 23:59:59
|
2038-01-19 03:14:07
|
||||||
select convert_tz('2038-01-01 01:00:00', 'MET', 'UTC');
|
select convert_tz('2038-01-19 04:14:08', 'MET', 'UTC');
|
||||||
convert_tz('2038-01-01 01:00:00', 'MET', 'UTC')
|
convert_tz('2038-01-19 04:14:08', 'MET', 'UTC')
|
||||||
2038-01-01 01:00:00
|
2038-01-19 04:14:08
|
||||||
select convert_tz('2103-01-01 04:00:00', 'MET', 'UTC');
|
select convert_tz('2103-01-01 04:00:00', 'MET', 'UTC');
|
||||||
convert_tz('2103-01-01 04:00:00', 'MET', 'UTC')
|
convert_tz('2103-01-01 04:00:00', 'MET', 'UTC')
|
||||||
2103-01-01 04:00:00
|
2103-01-01 04:00:00
|
||||||
|
|
6
mysql-test/r/timezone4.result
Normal file
6
mysql-test/r/timezone4.result
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
select from_unixtime(0);
|
||||||
|
from_unixtime(0)
|
||||||
|
1969-12-31 14:00:00
|
||||||
|
select unix_timestamp('1969-12-31 14:00:01');
|
||||||
|
unix_timestamp('1969-12-31 14:00:01')
|
||||||
|
1
|
|
@ -255,16 +255,56 @@ select unix_timestamp(@a);
|
||||||
select unix_timestamp('1969-12-01 19:00:01');
|
select unix_timestamp('1969-12-01 19:00:01');
|
||||||
|
|
||||||
#
|
#
|
||||||
# Test for bug #6439 "unix_timestamp() function returns wrong datetime
|
# Tests for bug #6439 "unix_timestamp() function returns wrong datetime
|
||||||
# values for too big argument" and bug #7515 "from_unixtime(0) now
|
# values for too big argument", bug #7515 "from_unixtime(0) now
|
||||||
# returns NULL instead of the epoch". unix_timestamp() should return error
|
# returns NULL instead of the epoch" and bug #9191
|
||||||
# for too big or negative argument. It should return Epoch value for zero
|
# "TIMESTAMP/from_unixtime() no longer accepts 2^31-1."
|
||||||
# argument since it seems that many user's rely on this fact.
|
# unix_timestamp() should return error for too big or negative argument.
|
||||||
|
# It should return Epoch value for zero argument since it seems that many
|
||||||
|
# users rely on this fact, from_unixtime() should work with values
|
||||||
|
# up to INT_MAX32 because of the same reason.
|
||||||
#
|
#
|
||||||
select from_unixtime(-1);
|
select from_unixtime(-1);
|
||||||
select from_unixtime(2145916800);
|
# check for from_unixtime(2^31-1) and from_unixtime(2^31)
|
||||||
|
select from_unixtime(2147483647);
|
||||||
|
select from_unixtime(2147483648);
|
||||||
select from_unixtime(0);
|
select from_unixtime(0);
|
||||||
|
|
||||||
|
#
|
||||||
|
# Some more tests for bug #9191 "TIMESTAMP/from_unixtime() no
|
||||||
|
# longer accepts 2^31-1". 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));
|
||||||
|
|
||||||
|
# check for invalid dates
|
||||||
|
|
||||||
|
# bad year
|
||||||
|
select unix_timestamp('2039-01-20 01:00:00');
|
||||||
|
select unix_timestamp('1968-01-20 01:00:00');
|
||||||
|
# bad month
|
||||||
|
select unix_timestamp('2038-02-10 01:00:00');
|
||||||
|
select unix_timestamp('1969-11-20 01:00:00');
|
||||||
|
# bad day
|
||||||
|
select unix_timestamp('2038-01-20 01:00:00');
|
||||||
|
select unix_timestamp('1969-12-30 01:00:00');
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check negative shift (we subtract several days for boundary dates during
|
||||||
|
# conversion).
|
||||||
|
select unix_timestamp('2038-01-17 12:00:00');
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check positive shift. (it happens only on
|
||||||
|
# platfroms with unsigned time_t, such as QNX)
|
||||||
|
#
|
||||||
|
select unix_timestamp('1970-01-01 03:00:01');
|
||||||
|
|
||||||
|
# check bad date, close to the boundary (we cut them off in the very end)
|
||||||
|
select unix_timestamp('2038-01-19 07:14:07');
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Test types from + INTERVAL
|
# Test types from + INTERVAL
|
||||||
#
|
#
|
||||||
|
|
|
@ -52,11 +52,12 @@ INSERT INTO t1 (ts) VALUES ('2003-03-30 01:59:59'),
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
#
|
#
|
||||||
# Test for fix for Bug#2523
|
# Test for fix for Bug#2523 Check that boundary dates are processed
|
||||||
|
# correctly.
|
||||||
#
|
#
|
||||||
select unix_timestamp('1970-01-01 01:00:00'),
|
select unix_timestamp('1970-01-01 01:00:00'),
|
||||||
unix_timestamp('1970-01-01 01:00:01'),
|
unix_timestamp('1970-01-01 01:00:01'),
|
||||||
unix_timestamp('2038-01-01 00:59:59'),
|
unix_timestamp('2038-01-19 04:14:07'),
|
||||||
unix_timestamp('2038-01-01 01:00:00');
|
unix_timestamp('2038-01-19 04:14:08');
|
||||||
|
|
||||||
# End of 4.1 tests
|
# End of 4.1 tests
|
||||||
|
|
|
@ -113,21 +113,21 @@ create table t1 (ts timestamp);
|
||||||
set time_zone='UTC';
|
set time_zone='UTC';
|
||||||
insert into t1 values ('0000-00-00 00:00:00'),('1969-12-31 23:59:59'),
|
insert into t1 values ('0000-00-00 00:00:00'),('1969-12-31 23:59:59'),
|
||||||
('1970-01-01 00:00:00'),('1970-01-01 00:00:01'),
|
('1970-01-01 00:00:00'),('1970-01-01 00:00:01'),
|
||||||
('2037-12-31 23:59:59'),('2038-01-01 00:00:00');
|
('2038-01-19 03:14:07'),('2038-01-19 03:14:08');
|
||||||
select * from t1;
|
select * from t1;
|
||||||
truncate table t1;
|
truncate table t1;
|
||||||
# MET time zone has range shifted by one hour
|
# MET time zone has range shifted by one hour
|
||||||
set time_zone='MET';
|
set time_zone='MET';
|
||||||
insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 00:30:00'),
|
insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 00:30:00'),
|
||||||
('1970-01-01 01:00:00'),('1970-01-01 01:00:01'),
|
('1970-01-01 01:00:00'),('1970-01-01 01:00:01'),
|
||||||
('2038-01-01 00:59:59'),('2038-01-01 01:00:00');
|
('2038-01-19 04:14:07'),('2038-01-19 04:14:08');
|
||||||
select * from t1;
|
select * from t1;
|
||||||
truncate table t1;
|
truncate table t1;
|
||||||
# same for +01:30 time zone
|
# same for +01:30 time zone
|
||||||
set time_zone='+01:30';
|
set time_zone='+01:30';
|
||||||
insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 01:00:00'),
|
insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 01:00:00'),
|
||||||
('1970-01-01 01:30:00'),('1970-01-01 01:30:01'),
|
('1970-01-01 01:30:00'),('1970-01-01 01:30:01'),
|
||||||
('2038-01-01 01:29:59'),('2038-01-01 01:30:00');
|
('2038-01-19 04:44:07'),('2038-01-19 04:44:08');
|
||||||
select * from t1;
|
select * from t1;
|
||||||
|
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
@ -177,8 +177,8 @@ select convert_tz('2003-10-26 01:00:00', 'MET', 'UTC');
|
||||||
select convert_tz('2003-10-26 02:00:00', 'MET', 'UTC');
|
select convert_tz('2003-10-26 02:00:00', 'MET', 'UTC');
|
||||||
select convert_tz('2003-10-26 02:59:59', 'MET', 'UTC');
|
select convert_tz('2003-10-26 02:59:59', 'MET', 'UTC');
|
||||||
select convert_tz('2003-10-26 04:00:00', 'MET', 'UTC');
|
select convert_tz('2003-10-26 04:00:00', 'MET', 'UTC');
|
||||||
select convert_tz('2038-01-01 00:59:59', 'MET', 'UTC');
|
select convert_tz('2038-01-19 04:14:07', 'MET', 'UTC');
|
||||||
select convert_tz('2038-01-01 01:00:00', 'MET', 'UTC');
|
select convert_tz('2038-01-19 04:14:08', 'MET', 'UTC');
|
||||||
select convert_tz('2103-01-01 04:00:00', 'MET', 'UTC');
|
select convert_tz('2103-01-01 04:00:00', 'MET', 'UTC');
|
||||||
|
|
||||||
# Let us test variable time zone argument
|
# Let us test variable time zone argument
|
||||||
|
|
1
mysql-test/t/timezone4-master.opt
Normal file
1
mysql-test/t/timezone4-master.opt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
--timezone=GMT+10
|
13
mysql-test/t/timezone4.test
Normal file
13
mysql-test/t/timezone4.test
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#
|
||||||
|
# Tests for time functions. The difference from func_time test is the
|
||||||
|
# timezone. In func_time it's GMT-3. In our case it's GMT+10
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test for bug bug #9191 "TIMESTAMP/from_unixtime() no longer accepts 2^31-1"
|
||||||
|
#
|
||||||
|
|
||||||
|
select from_unixtime(0);
|
||||||
|
# check 0 boundary
|
||||||
|
select unix_timestamp('1969-12-31 14:00:01');
|
||||||
|
|
|
@ -730,15 +730,27 @@ long calc_daynr(uint year,uint month,uint day)
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
Time in UTC seconds since Unix Epoch representation.
|
Time in UTC seconds since Unix Epoch representation.
|
||||||
*/
|
*/
|
||||||
my_time_t
|
my_time_t
|
||||||
my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone,
|
my_system_gmt_sec(const MYSQL_TIME *t_src, long *my_timezone,
|
||||||
my_bool *in_dst_time_gap)
|
bool *in_dst_time_gap)
|
||||||
{
|
{
|
||||||
uint loop;
|
uint loop;
|
||||||
time_t tmp;
|
time_t tmp= 0;
|
||||||
|
int shift= 0;
|
||||||
|
MYSQL_TIME tmp_time;
|
||||||
|
MYSQL_TIME *t= &tmp_time;
|
||||||
struct tm *l_time,tm_tmp;
|
struct tm *l_time,tm_tmp;
|
||||||
long diff, current_timezone;
|
long diff, current_timezone;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Use temp variable to avoid trashing input data, which could happen in
|
||||||
|
case of shift required for boundary dates processing.
|
||||||
|
*/
|
||||||
|
memcpy(&tmp_time, t_src, sizeof(MYSQL_TIME));
|
||||||
|
|
||||||
|
if (!validate_timestamp_range(t))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate the gmt time based on current time and timezone
|
Calculate the gmt time based on current time and timezone
|
||||||
The -1 on the end is to ensure that if have a date that exists twice
|
The -1 on the end is to ensure that if have a date that exists twice
|
||||||
|
@ -752,13 +764,89 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone,
|
||||||
Note: this code assumes that our time_t estimation is not too far away
|
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
|
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.
|
within 24 hrs from t) which is probably true for all current time zones.
|
||||||
*/
|
|
||||||
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);
|
|
||||||
current_timezone= my_time_zone;
|
|
||||||
|
|
||||||
|
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 these days to the final value.
|
||||||
|
|
||||||
|
The same trick is done for the values close to 0 in time_t
|
||||||
|
representation for platfroms with unsigned time_t (QNX).
|
||||||
|
|
||||||
|
To be more verbose, here is a sample (extracted from the code below):
|
||||||
|
(calc_daynr(2038, 1, 19) - (long) days_at_timestart)*86400L + 4*3600L
|
||||||
|
would return -2147480896 because of the long type overflow. In result
|
||||||
|
we would get 1901 year in localtime_r(), which is an obvious error.
|
||||||
|
|
||||||
|
Alike problem raises with the dates close to Epoch. E.g.
|
||||||
|
(calc_daynr(1969, 12, 31) - (long) days_at_timestart)*86400L + 23*3600L
|
||||||
|
will give -3600.
|
||||||
|
|
||||||
|
On some platforms, (E.g. on QNX) time_t is unsigned and localtime(-3600)
|
||||||
|
wil give us a date around 2106 year. Which is no good.
|
||||||
|
|
||||||
|
Theoreticaly, there could be problems with the latter conversion:
|
||||||
|
there are at least two timezones, which had time switches near 1 Jan
|
||||||
|
of 1970 (because of political reasons). These are America/Hermosillo and
|
||||||
|
America/Mazatlan time zones. They changed their offset on
|
||||||
|
1970-01-01 08:00:00 UTC from UTC-8 to UTC-7. For these zones
|
||||||
|
the code below will give incorrect results for dates close to
|
||||||
|
1970-01-01, in the case OS takes into account these historical switches.
|
||||||
|
Luckily, it seems that we support only one platform with unsigned
|
||||||
|
time_t. It's QNX. And QNX does not support historical timezone data at all.
|
||||||
|
E.g. there are no /usr/share/zoneinfo/ files or any other mean to supply
|
||||||
|
historical information for localtime_r() etc. That is, the problem is not
|
||||||
|
relevant to QNX.
|
||||||
|
|
||||||
|
We are safe with shifts close to MAX_INT32, as there are no known
|
||||||
|
time switches on Jan 2038 yet :)
|
||||||
|
*/
|
||||||
|
if ((t->year == TIMESTAMP_MAX_YEAR) && (t->month == 1) && (t->day > 4))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Below we will pass (uint) (t->day - shift) to calc_daynr.
|
||||||
|
As we don't want to get an overflow here, we will shift
|
||||||
|
only safe dates. That's why we have (t->day > 4) above.
|
||||||
|
*/
|
||||||
|
t->day-= 2;
|
||||||
|
shift= 2;
|
||||||
|
}
|
||||||
|
#ifdef TIME_T_UNSIGNED
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We can get 0 in time_t representaion only on 1969, 31 of Dec or on
|
||||||
|
1970, 1 of Jan. For both dates we use shift, which is added
|
||||||
|
to t->day in order to step out a bit from the border.
|
||||||
|
This is required for platforms, where time_t is unsigned.
|
||||||
|
As far as I know, among the platforms we support it's only QNX.
|
||||||
|
Note: the order of below if-statements is significant.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((t->year == TIMESTAMP_MIN_YEAR + 1) && (t->month == 1)
|
||||||
|
&& (t->day <= 10))
|
||||||
|
{
|
||||||
|
t->day+= 2;
|
||||||
|
shift= -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((t->year == TIMESTAMP_MIN_YEAR) && (t->month == 12)
|
||||||
|
&& (t->day == 31))
|
||||||
|
{
|
||||||
|
t->year++;
|
||||||
|
t->month= 1;
|
||||||
|
t->day= 2;
|
||||||
|
shift= -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
current_timezone= my_time_zone;
|
||||||
localtime_r(&tmp,&tm_tmp);
|
localtime_r(&tmp,&tm_tmp);
|
||||||
l_time=&tm_tmp;
|
l_time=&tm_tmp;
|
||||||
for (loop=0;
|
for (loop=0;
|
||||||
|
@ -810,7 +898,24 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone,
|
||||||
*in_dst_time_gap= 1;
|
*in_dst_time_gap= 1;
|
||||||
}
|
}
|
||||||
*my_timezone= current_timezone;
|
*my_timezone= current_timezone;
|
||||||
|
|
||||||
|
|
||||||
|
/* shift back, if we were dealing with boundary dates */
|
||||||
|
tmp+= shift*86400L;
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is possible for dates, which slightly exceed boundaries.
|
||||||
|
Conversion will pass ok for them, but we don't allow them.
|
||||||
|
First check will pass for platforms with signed time_t.
|
||||||
|
instruction above (tmp+= shift*86400L) could exceed
|
||||||
|
MAX_INT32 (== TIMESTAMP_MAX_VALUE) and overflow will happen.
|
||||||
|
So, tmp < TIMESTAMP_MIN_VALUE will be triggered. On platfroms
|
||||||
|
with unsigned time_t tmp+= shift*86400L might result in a number,
|
||||||
|
larger then TIMESTAMP_MAX_VALUE, so another check will work.
|
||||||
|
*/
|
||||||
|
if ((tmp < TIMESTAMP_MIN_VALUE) || (tmp > TIMESTAMP_MAX_VALUE))
|
||||||
|
tmp= 0;
|
||||||
|
end:
|
||||||
return (my_time_t) tmp;
|
return (my_time_t) tmp;
|
||||||
} /* my_system_gmt_sec */
|
} /* my_system_gmt_sec */
|
||||||
|
|
||||||
|
|
|
@ -1911,17 +1911,14 @@ bool Item_func_convert_tz::get_date(TIME *ltime,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we in range where we treat datetime values as non-UTC */
|
|
||||||
if (ltime->year < TIMESTAMP_MAX_YEAR && ltime->year > TIMESTAMP_MIN_YEAR ||
|
|
||||||
ltime->year==TIMESTAMP_MAX_YEAR && ltime->month==1 && ltime->day==1 ||
|
|
||||||
ltime->year==TIMESTAMP_MIN_YEAR && ltime->month==12 && ltime->day==31)
|
|
||||||
{
|
{
|
||||||
my_bool not_used;
|
my_bool not_used;
|
||||||
my_time_tmp= from_tz->TIME_to_gmt_sec(ltime, ¬_used);
|
my_time_tmp= from_tz->TIME_to_gmt_sec(ltime, ¬_used);
|
||||||
if (my_time_tmp >= TIMESTAMP_MIN_VALUE && my_time_tmp <= TIMESTAMP_MAX_VALUE)
|
/* my_time_tmp is guranteed to be in the allowed range */
|
||||||
|
if (my_time_tmp)
|
||||||
to_tz->gmt_sec_to_TIME(ltime, my_time_tmp);
|
to_tz->gmt_sec_to_TIME(ltime, my_time_tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
null_value= 0;
|
null_value= 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,12 +223,6 @@ MY_LOCALE *my_locale_by_name(const char *name);
|
||||||
/* Characters shown for the command in 'information_schema.processlist' */
|
/* Characters shown for the command in 'information_schema.processlist' */
|
||||||
#define PROCESS_LIST_INFO_WIDTH 65535
|
#define PROCESS_LIST_INFO_WIDTH 65535
|
||||||
|
|
||||||
/* 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_DOUBLE 53
|
||||||
#define PRECISION_FOR_FLOAT 24
|
#define PRECISION_FOR_FLOAT 24
|
||||||
|
|
||||||
|
|
|
@ -253,14 +253,11 @@ my_time_t TIME_to_timestamp(THD *thd, const TIME *t, my_bool *in_dst_time_gap)
|
||||||
|
|
||||||
*in_dst_time_gap= 0;
|
*in_dst_time_gap= 0;
|
||||||
|
|
||||||
if (t->year < TIMESTAMP_MAX_YEAR && t->year > TIMESTAMP_MIN_YEAR ||
|
timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap);
|
||||||
t->year == TIMESTAMP_MAX_YEAR && t->month == 1 && t->day == 1 ||
|
if (timestamp)
|
||||||
t->year == TIMESTAMP_MIN_YEAR && t->month == 12 && t->day == 31)
|
|
||||||
{
|
{
|
||||||
thd->time_zone_used= 1;
|
thd->time_zone_used= 1;
|
||||||
timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap);
|
return timestamp;
|
||||||
if (timestamp >= TIMESTAMP_MIN_VALUE && timestamp <= TIMESTAMP_MAX_VALUE)
|
|
||||||
return timestamp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we are here we have range error. */
|
/* If we are here we have range error. */
|
||||||
|
|
|
@ -898,8 +898,14 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp,
|
||||||
my_time_t local_t;
|
my_time_t local_t;
|
||||||
uint saved_seconds;
|
uint saved_seconds;
|
||||||
uint i;
|
uint i;
|
||||||
|
int shift= 0;
|
||||||
|
|
||||||
DBUG_ENTER("TIME_to_gmt_sec");
|
DBUG_ENTER("TIME_to_gmt_sec");
|
||||||
|
|
||||||
|
if (!validate_timestamp_range(t))
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
|
|
||||||
/* We need this for correct leap seconds handling */
|
/* We need this for correct leap seconds handling */
|
||||||
if (t->second < SECS_PER_MIN)
|
if (t->second < SECS_PER_MIN)
|
||||||
saved_seconds= 0;
|
saved_seconds= 0;
|
||||||
|
@ -907,11 +913,29 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp,
|
||||||
saved_seconds= t->second;
|
saved_seconds= t->second;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NOTE If we want to convert full my_time_t range without MySQL
|
NOTE: to convert full my_time_t range we do a shift of the
|
||||||
restrictions we should catch overflow here somehow.
|
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,
|
t->hour, t->minute,
|
||||||
saved_seconds ? 0 : t->second);
|
saved_seconds ? 0 : t->second);
|
||||||
|
|
||||||
|
@ -930,6 +954,22 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp,
|
||||||
/* binary search for our range */
|
/* binary search for our range */
|
||||||
i= find_time_range(local_t, sp->revts, sp->revcnt);
|
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)
|
if (sp->revtis[i].rt_type)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -939,10 +979,16 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp,
|
||||||
beginning of the gap.
|
beginning of the gap.
|
||||||
*/
|
*/
|
||||||
*in_dst_time_gap= 1;
|
*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
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1308,9 +1354,24 @@ Time_zone_offset::Time_zone_offset(long tz_offset_arg):
|
||||||
my_time_t
|
my_time_t
|
||||||
Time_zone_offset::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
|
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,
|
my_time_t local_t;
|
||||||
t->hour, t->minute, t->second) -
|
|
||||||
offset;
|
/*
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue