Commit 6f55cb4b authored by Sergei Golubchik's avatar Sergei Golubchik Committed by Rucha Deodhar

MDEV-31684 post-review changes

parent 94eb8192
......@@ -556,9 +556,10 @@ select time_format('2001-01-01 02:02:02', '%T');
time_format('2001-01-01 02:02:02', '%T')
02:02:02
#
# Beginning of 11.3 test
# End of 10.2 test
#
# MDEV-31684: Add timezone information to DATE_FORMAT
#
# MDEV-31684 Add timezone information to DATE_FORMAT
#
SET @old_timezone= @@time_zone;
# Using named timezones
......@@ -590,14 +591,7 @@ SET TIME_ZONE='UTC';
SELECT DATE_FORMAT('2009-10-04 22:23:00', '%z %Z') AS current_timezone;
current_timezone
+0000 UTC
# using system time
#
# output depends on system time information. Hence replacing
# to avoid result diff test failures.
#
SET @@time_zone= default;
SELECT DATE_FORMAT('2009-10+|-HH:MM ABC22:23:00', '%z %Z') AS current_timezone;
current_timezone
+|-HH:MM ABC
SET @@time_zone= @old_timezone;
#
# End of 11.3 test
#
......@@ -258,9 +258,11 @@ select time_format('01 02:02:02', '%T');
select time_format('2001-01-01 02:02:02', '%T');
--echo #
--echo # Beginning of 11.3 test
--echo # End of 10.2 test
--echo #
--echo # MDEV-31684: Add timezone information to DATE_FORMAT
--echo #
--echo # MDEV-31684 Add timezone information to DATE_FORMAT
--echo #
SET @old_timezone= @@time_zone;
......@@ -290,17 +292,8 @@ SELECT DATE_FORMAT('2009-10-04 22:23:00', '%z %Z') AS current_timezone;
SET TIME_ZONE='UTC';
SELECT DATE_FORMAT('2009-10-04 22:23:00', '%z %Z') AS current_timezone;
--echo # using system time
--echo #
--echo # output depends on system time information. Hence replacing
--echo # to avoid result diff test failures.
--echo #
SET @@time_zone= default;
--replace_regex /[+-][0-9]* [A-Z]*/+|-HH:MM ABC/
SELECT DATE_FORMAT('2009-10-04 22:23:00', '%z %Z') AS current_timezone;
SET @@time_zone= @old_timezone;
--echo #
--echo # End of 11.3 test
--echo #
......@@ -75,3 +75,14 @@ alter table mysql.time_zone_transition_type add primary key (time_zone_id,transi
#
# End of 10.8 tests
#
#
# MDEV-31684 Add timezone information to DATE_FORMAT
#
# using system time
SET @@time_zone= default;
SELECT DATE_FORMAT('2009-11-01 22:23:00', '%z %Z') AS current_timezone;
current_timezone
+0100 MET
SELECT DATE_FORMAT('2008-06-04 02:23:00', '%z %Z') AS current_timezone;
current_timezone
+0200 MEST
......@@ -74,3 +74,12 @@ alter table mysql.time_zone_transition_type add primary key (time_zone_id,transi
--echo #
--echo # End of 10.8 tests
--echo #
--echo #
--echo # MDEV-31684 Add timezone information to DATE_FORMAT
--echo #
--echo # using system time
SET @@time_zone= default;
SELECT DATE_FORMAT('2009-11-01 22:23:00', '%z %Z') AS current_timezone;
SELECT DATE_FORMAT('2008-06-04 02:23:00', '%z %Z') AS current_timezone;
......@@ -482,15 +482,8 @@ static bool make_date_time(THD *thd, const String *format,
uint weekday;
ulong length;
const char *ptr, *end;
int diff_hr=0, diff_min=0;
char abbrevation[8];
struct tz tmp;
tmp.is_inited= false;
Time_zone* curr_timezone= my_tz_find(thd,
thd->variables.time_zone->get_name());
memset(abbrevation, 0, sizeof(abbrevation));
struct tz curr_tz;
Time_zone* curr_timezone= 0;
str->length(0);
......@@ -710,41 +703,29 @@ static bool make_date_time(THD *thd, const String *format,
case 'z':
{
if (!tmp.is_inited)
if (!curr_timezone)
{
curr_timezone->get_timezone_information(&tmp, l_time);
tmp.is_inited= true;
curr_timezone= thd->variables.time_zone;
curr_timezone->get_timezone_information(&curr_tz, l_time);
}
ulonglong seconds= abs(tmp.seconds_offset);
diff_hr= (int)(seconds/3600L);
int temp= (int)(seconds%3600L);
diff_min= temp/60L;
if (tmp.is_behind)
str->append("-", 1);
else
str->append("+", 1);
if (diff_hr/10 == 0)
str->append("0", 1);
length= (uint) (int10_to_str(diff_hr, intbuff, 10) - intbuff);
str->append(intbuff, length);
if (diff_min/10 == 0)
str->append("0", 1);
length= (uint) (int10_to_str(diff_min, intbuff, 10) - intbuff);
str->append(intbuff, length);
}
long minutes= labs(curr_tz.seconds_offset)/60, diff_hr, diff_min;
diff_hr= minutes/60;
diff_min= minutes%60;
str->append(curr_tz.seconds_offset < 0 ? '-' : '+');
str->append(static_cast<char>('0' + diff_hr/10));
str->append(static_cast<char>('0' + diff_hr%10));
str->append(static_cast<char>('0' + diff_min/10));
str->append(static_cast<char>('0' + diff_min%10));
break;
}
case 'Z':
{
if (!tmp.is_inited)
if (!curr_timezone)
{
curr_timezone->get_timezone_information(&tmp, l_time);
tmp.is_inited= true;
curr_timezone= thd->variables.time_zone;
curr_timezone->get_timezone_information(&curr_tz, l_time);
}
str->append(tmp.abbrevation, strlen(tmp.abbrevation));
}
str->append(curr_tz.abbrevation, strlen(curr_tz.abbrevation));
break;
default:
str->append(*ptr);
......@@ -1874,6 +1855,7 @@ uint Item_func_date_format::format_length(const String *format)
case 'X': /* Year, used with 'v, where week starts with Monday' */
size += 4;
break;
case 'Z': /* time zone abbreviation */
case 'a': /* locale's abbreviated weekday name (Sun..Sat) */
case 'b': /* locale's abbreviated month name (Jan.Dec) */
size += 32; /* large for UTF8 locale data */
......@@ -1912,6 +1894,9 @@ uint Item_func_date_format::format_length(const String *format)
case 'f': /* microseconds */
size += 6;
break;
case 'z': /* time zone offset */
size += 5;
break;
case 'w': /* day (of the week), numeric */
case '%':
default:
......
......@@ -52,23 +52,12 @@
#include <mysql/psi/mysql_file.h>
#include "lock.h" // MYSQL_LOCK_IGNORE_FLUSH,
// MYSQL_LOCK_IGNORE_TIMEOUT
/*
Now we don't use abbreviations in server but we will do this in future.
Edit: Started needing abbrevation in server as part of task MDEV-31684.
*/
#ifndef ABBR_ARE_USED
#define ABBR_ARE_USED
#endif /* defined(TZINFO2SQL) || defined(TESTTIME) */
/* Structure describing local time type (e.g. Moscow summer time (MSD)) */
typedef struct ttinfo
{
long tt_gmtoff; // Offset from UTC in seconds
uint tt_isdst; // Is daylight saving time or not. Used to set tm_isdst
#ifdef ABBR_ARE_USED
uint tt_abbrind; // Index of start of abbreviation for this time type.
#endif
/*
We don't use tt_ttisstd and tt_ttisgmt members of original elsie-code
struct since we don't support POSIX-style TZ descriptions in variables.
......@@ -115,10 +104,8 @@ typedef struct st_time_zone_info
my_time_t *ats; // Times of transitions between time types
uchar *types; // Local time types for transitions
TRAN_TYPE_INFO *ttis; // Local time types descriptions
#ifdef ABBR_ARE_USED
/* Storage for local time types abbreviations. They are stored as ASCIIZ */
char *chars;
#endif
/*
Leap seconds corrections descriptions, this array is shared by
all time zones who use leap seconds.
......@@ -174,9 +161,7 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
struct tzhead tzhead;
uchar buf[sizeof(struct tzhead) + sizeof(my_time_t) * TZ_MAX_TIMES +
TZ_MAX_TIMES + sizeof(TRAN_TYPE_INFO) * TZ_MAX_TYPES +
#ifdef ABBR_ARE_USED
MY_MAX(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1))) +
#endif
sizeof(LS_INFO) * TZ_MAX_LEAPS];
} u;
uint ttisstdcnt;
......@@ -221,9 +206,7 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
ALIGN_SIZE(sp->timecnt) +
ALIGN_SIZE(sp->typecnt *
sizeof(TRAN_TYPE_INFO)) +
#ifdef ABBR_ARE_USED
ALIGN_SIZE(sp->charcnt+1) +
#endif
sp->leapcnt * sizeof(LS_INFO))))
return 1;
......@@ -233,10 +216,8 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
tzinfo_buf+= ALIGN_SIZE(sp->timecnt);
sp->ttis= (TRAN_TYPE_INFO *)tzinfo_buf;
tzinfo_buf+= ALIGN_SIZE(sp->typecnt * sizeof(TRAN_TYPE_INFO));
#ifdef ABBR_ARE_USED
sp->chars= tzinfo_buf;
tzinfo_buf+= ALIGN_SIZE(sp->charcnt+1);
#endif
sp->lsis= (LS_INFO *)tzinfo_buf;
for (i= 0; i < sp->timecnt; i++, p+= 4)
......@@ -1096,20 +1077,45 @@ Time_zone_system::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
void
Time_zone_system::get_timezone_information(struct tz* curr_tz, const MYSQL_TIME *local_TIME) const
{
#ifndef _WIN32
uint error;
struct tm tm_local_time;
time_t time_sec= this->TIME_to_gmt_sec(local_TIME, &error);
time_t time_sec= TIME_to_gmt_sec(local_TIME, &error);
localtime_r(&time_sec, &tm_local_time);
# ifdef __USE_MISC
int len= strlen((tm_local_time.tm_zone));
strmake(curr_tz->abbrevation, tm_local_time.tm_zone, sizeof(tm_local_time.tm_zone)-1);
curr_tz->abbrevation[len]= '\0';
# endif
curr_tz->seconds_offset= tm_local_time.tm_gmtoff;
curr_tz->is_behind= tm_local_time.tm_gmtoff < 0;
strmake_buf(curr_tz->abbrevation, tm_local_time.tm_zone);
curr_tz->seconds_offset= tm_local_time.tm_gmtoff;
#else
#define mdHMS(mon,day,h,m,s) (((((mon)*100+(day))*100+(h))*100+(m))*100+(s))
TIME_ZONE_INFORMATION tzi;
bool use_dst= false;
GetTimeZoneInformationForYear(local_TIME->year, NULL, &tzi);
if (tzi.StandardDate.wMonth)
{
ulonglong std= mdHMS(tzi.StandardDate.wMonth, tzi.StandardDate.wDay,
tzi.StandardDate.wHour, tzi.StandardDate.wMinute,
tzi.StandardDate.wSecond);
ulonglong dst= mdHMS(tzi.DaylightDate.wMonth, tzi.DaylightDate.wDay,
tzi.DaylightDate.wHour, tzi.DaylightDate.wMinute,
tzi.DaylightDate.wSecond);
ulonglong cur= mdHMS(local_TIME->month, local_TIME->day, local_TIME->hour,
local_TIME->minute, local_TIME->second);
use_dst= std < dst ? cur < std || cur >= dst : cur >= dst && cur < std;
}
if (use_dst)
{
size_t len;
curr_tz->seconds_offset= -60 * (tzi.Bias + tzi.DaylightBias);
wcstombs_s(&len, curr_tz->abbrevation, sizeof(curr_tz->abbrevation),
tzi.DaylightName, _TRUNCATE);
}
else
{
size_t len;
curr_tz->seconds_offset= -60 * (tzi.Bias + tzi.StandardBias);
wcstombs_s(&len, curr_tz->abbrevation, sizeof(curr_tz->abbrevation),
tzi.StandardName, _TRUNCATE);
}
#endif
}
......@@ -1194,17 +1200,8 @@ Time_zone_utc::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
void
Time_zone_utc::get_timezone_information(struct tz* curr_tz, const MYSQL_TIME *local_TIME) const
{
uint error;
struct tm tm_local_time;
time_t time_sec= this->TIME_to_gmt_sec(local_TIME, &error);
localtime_r(&time_sec, &tm_local_time);
# ifdef __USE_MISC
strmake(curr_tz->abbrevation, "UTC", 3);
# endif
curr_tz->seconds_offset= tm_local_time.tm_gmtoff;
curr_tz->is_behind= tm_local_time.tm_gmtoff < 0;
strmake_buf(curr_tz->abbrevation, "UTC");
curr_tz->seconds_offset= 0;
}
......@@ -1321,14 +1318,12 @@ Time_zone_db::get_timezone_information(struct tz* curr_tz, const MYSQL_TIME *loc
const TRAN_TYPE_INFO *ttisp;
/* Get seconds since epoch. */
sec_in_utc= this->TIME_to_gmt_sec(local_TIME, &error);
sec_in_utc= TIME_to_gmt_sec(local_TIME, &error);
/* Get local timezone information. */
ttisp= find_transition_type(sec_in_utc, tz_info);
curr_tz->seconds_offset= ttisp->tt_gmtoff;
curr_tz->is_behind= tz_info->revtis->rt_offset < 0 ? true : false;
strmake(curr_tz->abbrevation, &(tz_info->chars[ttisp->tt_abbrind]), tz_info->charcnt-1);
strmake_buf(curr_tz->abbrevation, &(tz_info->chars[ttisp->tt_abbrind]));
}
......@@ -1491,8 +1486,7 @@ Time_zone_offset::get_timezone_information(struct tz* curr_tz, const MYSQL_TIME
{
curr_tz->seconds_offset= offset;
const char *name= get_name()->ptr();
curr_tz->is_behind= name[0] == '+' ? false : true;
strmake(curr_tz->abbrevation, name, sizeof(curr_tz->abbrevation)-1);
strmake_buf(curr_tz->abbrevation, name);
}
......@@ -1933,9 +1927,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
my_time_t ats[TZ_MAX_TIMES];
uchar types[TZ_MAX_TIMES];
TRAN_TYPE_INFO ttis[TZ_MAX_TYPES];
#ifdef ABBR_ARE_USED
char chars[MY_MAX(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1)))];
#endif
/*
Used as a temporary tz_info until we decide that we actually want to
allocate and keep the tz info and tz name in tz_storage.
......@@ -2041,7 +2033,6 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
ttis[ttid].tt_gmtoff= (long)table->field[2]->val_int();
ttis[ttid].tt_isdst= (table->field[3]->val_int() > 0);
#ifdef ABBR_ARE_USED
// FIXME should we do something with duplicates here ?
table->field[4]->val_str(&abbr, &abbr);
if (tmp_tz_info.charcnt + abbr.length() + 1 > sizeof(chars))
......@@ -2061,11 +2052,6 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
("time_zone_transition_type table: tz_id=%u tt_id=%u tt_gmtoff=%ld "
"abbr='%s' tt_isdst=%u", tzid, ttid, ttis[ttid].tt_gmtoff,
chars + ttis[ttid].tt_abbrind, ttis[ttid].tt_isdst));
#else
DBUG_PRINT("info",
("time_zone_transition_type table: tz_id=%u tt_id=%u tt_gmtoff=%ld "
"tt_isdst=%u", tzid, ttid, ttis[ttid].tt_gmtoff, ttis[ttid].tt_isdst));
#endif
/* ttid is increasing because we are reading using index */
if (ttid < tmp_tz_info.typecnt)
......@@ -2181,9 +2167,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
ALIGN_SIZE(sizeof(my_time_t) *
tz_info->timecnt) +
ALIGN_SIZE(tz_info->timecnt) +
#ifdef ABBR_ARE_USED
ALIGN_SIZE(tz_info->charcnt) +
#endif
sizeof(TRAN_TYPE_INFO) *
tz_info->typecnt)))
{
......@@ -2197,11 +2181,9 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
tz_info->types= (uchar *)alloc_buff;
memcpy(tz_info->types, types, tz_info->timecnt);
alloc_buff+= ALIGN_SIZE(tz_info->timecnt);
#ifdef ABBR_ARE_USED
tz_info->chars= alloc_buff;
memcpy(tz_info->chars, chars, tz_info->charcnt);
alloc_buff+= ALIGN_SIZE(tz_info->charcnt);
#endif
tz_info->ttis= (TRAN_TYPE_INFO *)alloc_buff;
memcpy(tz_info->ttis, ttis, tz_info->typecnt * sizeof(TRAN_TYPE_INFO));
......
......@@ -32,25 +32,22 @@ class THD;
class THD;
/**
This class represents abstract time zone and provides
basic interface for MYSQL_TIME <-> my_time_t conversion.
Actual time zones which are specified by DB, or via offset
or use system functions are its descendants.
*/
/*
Has only offset from UTC, bool value to denote if it is
ahead (+), behind(-) of UTC and abbrevation.
Has only offset from UTC and abbrevation.
*/
struct tz
{
long seconds_offset;
bool is_behind;
char abbrevation[8];
bool is_inited;
char abbrevation[64];
};
/**
This class represents abstract time zone and provides
basic interface for MYSQL_TIME <-> my_time_t conversion.
Actual time zones which are specified by DB, or via offset
or use system functions are its descendants.
*/
class Time_zone: public Sql_alloc
{
public:
......
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