You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-07-29 08:21:15 +03:00
MCOL-1356: Add convert_tz (#2099)
This commit is contained in:
600
dbcon/mysql/ha_tzinfo.cpp
Normal file
600
dbcon/mysql/ha_tzinfo.cpp
Normal file
@ -0,0 +1,600 @@
|
||||
/* Copyright (C) 2021 MariaDB Corporation
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; version 2 of
|
||||
the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA. */
|
||||
|
||||
#include "ha_tzinfo.h"
|
||||
#include "tzfile.h"
|
||||
#include <my_sys.h>
|
||||
|
||||
/* needed for sql_base.h which contains open_system_tables_for_read*/
|
||||
#ifndef TRUE
|
||||
#define TRUE (1) /* Logical true */
|
||||
#define FALSE (0) /* Logical false */
|
||||
#endif
|
||||
#include <sql_base.h>
|
||||
|
||||
//static HASH tz_names;
|
||||
//static HASH offset_tzs;
|
||||
static MEM_ROOT tz_storage;
|
||||
static uint tz_leapcnt= 0;
|
||||
static LS_INFO *tz_lsis= 0;
|
||||
static bool time_zone_tables_exist= 1;
|
||||
|
||||
namespace cal_impl_if
|
||||
{
|
||||
|
||||
/*
|
||||
Names of tables (with their lengths) that are needed
|
||||
for dynamical loading of time zone descriptions.
|
||||
*/
|
||||
|
||||
static const LEX_CSTRING tz_tables_names[MY_TZ_TABLES_COUNT]=
|
||||
{
|
||||
{ STRING_WITH_LEN("time_zone_name")},
|
||||
{ STRING_WITH_LEN("time_zone")},
|
||||
{ STRING_WITH_LEN("time_zone_transition_type")},
|
||||
{ STRING_WITH_LEN("time_zone_transition")}
|
||||
};
|
||||
|
||||
static void
|
||||
tz_init_table_list(TABLE_LIST *tz_tabs)
|
||||
{
|
||||
for (int i= 0; i < MY_TZ_TABLES_COUNT; i++)
|
||||
{
|
||||
tz_tabs[i].init_one_table(&MYSQL_SCHEMA_NAME, tz_tables_names + i,
|
||||
NULL, TL_READ);
|
||||
if (i != MY_TZ_TABLES_COUNT - 1)
|
||||
tz_tabs[i].next_global= tz_tabs[i].next_local= &tz_tabs[i+1];
|
||||
if (i != 0)
|
||||
tz_tabs[i].prev_global= &tz_tabs[i-1].next_global;
|
||||
}
|
||||
}
|
||||
|
||||
static my_bool
|
||||
prepare_tz_info(TIME_ZONE_INFO *sp, MEM_ROOT *storage)
|
||||
{
|
||||
my_time_t cur_t= MY_TIME_T_MIN;
|
||||
my_time_t cur_l, end_t;
|
||||
my_time_t end_l = 0;
|
||||
my_time_t cur_max_seen_l= MY_TIME_T_MIN;
|
||||
long cur_offset, cur_corr, cur_off_and_corr;
|
||||
uint next_trans_idx, next_leap_idx;
|
||||
uint i;
|
||||
/*
|
||||
Temporary arrays where we will store tables. Needed because
|
||||
we don't know table sizes ahead. (Well we can estimate their
|
||||
upper bound but this will take extra space.)
|
||||
*/
|
||||
my_time_t revts[TZ_MAX_REV_RANGES];
|
||||
REVT_INFO revtis[TZ_MAX_REV_RANGES];
|
||||
|
||||
/*
|
||||
Let us setup fallback time type which will be used if we have not any
|
||||
transitions or if we have moment of time before first transition.
|
||||
We will find first non-DST local time type and use it (or use first
|
||||
local time type if all of them are DST types).
|
||||
*/
|
||||
for (i= 0; i < sp->typecnt && sp->ttis[i].tt_isdst; i++)
|
||||
/* no-op */ ;
|
||||
if (i == sp->typecnt)
|
||||
i= 0;
|
||||
sp->fallback_tti= &(sp->ttis[i]);
|
||||
|
||||
|
||||
/*
|
||||
Let us build shifted my_time_t -> my_time_t map.
|
||||
*/
|
||||
sp->revcnt= 0;
|
||||
|
||||
/* Let us find initial offset */
|
||||
if (sp->timecnt == 0 || cur_t < sp->ats[0])
|
||||
{
|
||||
/*
|
||||
If we have not any transitions or t is before first transition we are using
|
||||
already found fallback time type which index is already in i.
|
||||
*/
|
||||
next_trans_idx= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* cur_t == sp->ats[0] so we found transition */
|
||||
i= sp->types[0];
|
||||
next_trans_idx= 1;
|
||||
}
|
||||
|
||||
cur_offset= sp->ttis[i].tt_gmtoff;
|
||||
|
||||
|
||||
/* let us find leap correction... unprobable, but... */
|
||||
for (next_leap_idx= 0; next_leap_idx < sp->leapcnt &&
|
||||
cur_t >= sp->lsis[next_leap_idx].ls_trans;
|
||||
++next_leap_idx)
|
||||
continue;
|
||||
|
||||
if (next_leap_idx > 0)
|
||||
cur_corr= sp->lsis[next_leap_idx - 1].ls_corr;
|
||||
else
|
||||
cur_corr= 0;
|
||||
|
||||
/* Iterate trough t space */
|
||||
while (sp->revcnt < TZ_MAX_REV_RANGES - 1)
|
||||
{
|
||||
cur_off_and_corr= cur_offset - cur_corr;
|
||||
|
||||
/*
|
||||
We assuming that cur_t could be only overflowed downwards,
|
||||
we also assume that end_t won't be overflowed in this case.
|
||||
*/
|
||||
if (cur_off_and_corr < 0 &&
|
||||
cur_t < MY_TIME_T_MIN - cur_off_and_corr)
|
||||
cur_t= MY_TIME_T_MIN - cur_off_and_corr;
|
||||
|
||||
cur_l= cur_t + cur_off_and_corr;
|
||||
|
||||
/*
|
||||
Let us choose end_t as point before next time type change or leap
|
||||
second correction.
|
||||
*/
|
||||
end_t= MY_MIN((next_trans_idx < sp->timecnt) ? sp->ats[next_trans_idx] - 1:
|
||||
MY_TIME_T_MAX,
|
||||
(next_leap_idx < sp->leapcnt) ?
|
||||
sp->lsis[next_leap_idx].ls_trans - 1: MY_TIME_T_MAX);
|
||||
/*
|
||||
again assuming that end_t can be overlowed only in positive side
|
||||
we also assume that end_t won't be overflowed in this case.
|
||||
*/
|
||||
if (cur_off_and_corr > 0 &&
|
||||
end_t > MY_TIME_T_MAX - cur_off_and_corr)
|
||||
end_t= MY_TIME_T_MAX - cur_off_and_corr;
|
||||
|
||||
end_l= end_t + cur_off_and_corr;
|
||||
|
||||
|
||||
if (end_l > cur_max_seen_l)
|
||||
{
|
||||
/* We want special handling in the case of first range */
|
||||
if (cur_max_seen_l == MY_TIME_T_MIN)
|
||||
{
|
||||
revts[sp->revcnt]= cur_l;
|
||||
revtis[sp->revcnt].rt_offset= cur_off_and_corr;
|
||||
revtis[sp->revcnt].rt_type= 0;
|
||||
sp->revcnt++;
|
||||
cur_max_seen_l= end_l;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cur_l > cur_max_seen_l + 1)
|
||||
{
|
||||
/* We have a spring time-gap and we are not at the first range */
|
||||
revts[sp->revcnt]= cur_max_seen_l + 1;
|
||||
revtis[sp->revcnt].rt_offset= revtis[sp->revcnt-1].rt_offset;
|
||||
revtis[sp->revcnt].rt_type= 1;
|
||||
sp->revcnt++;
|
||||
if (sp->revcnt == TZ_MAX_TIMES + TZ_MAX_LEAPS + 1)
|
||||
break; /* That was too much */
|
||||
cur_max_seen_l= cur_l - 1;
|
||||
}
|
||||
|
||||
/* Assume here end_l > cur_max_seen_l (because end_l>=cur_l) */
|
||||
|
||||
revts[sp->revcnt]= cur_max_seen_l + 1;
|
||||
revtis[sp->revcnt].rt_offset= cur_off_and_corr;
|
||||
revtis[sp->revcnt].rt_type= 0;
|
||||
sp->revcnt++;
|
||||
cur_max_seen_l= end_l;
|
||||
}
|
||||
}
|
||||
|
||||
if (end_t == MY_TIME_T_MAX ||
|
||||
((cur_off_and_corr > 0) &&
|
||||
(end_t >= MY_TIME_T_MAX - cur_off_and_corr)))
|
||||
/* end of t space */
|
||||
break;
|
||||
|
||||
cur_t= end_t + 1;
|
||||
|
||||
/*
|
||||
Let us find new offset and correction. Because of our choice of end_t
|
||||
cur_t can only be point where new time type starts or/and leap
|
||||
correction is performed.
|
||||
*/
|
||||
if (sp->timecnt != 0 && cur_t >= sp->ats[0]) /* else reuse old offset */
|
||||
if (next_trans_idx < sp->timecnt &&
|
||||
cur_t == sp->ats[next_trans_idx])
|
||||
{
|
||||
/* We are at offset point */
|
||||
cur_offset= sp->ttis[sp->types[next_trans_idx]].tt_gmtoff;
|
||||
++next_trans_idx;
|
||||
}
|
||||
|
||||
if (next_leap_idx < sp->leapcnt &&
|
||||
cur_t == sp->lsis[next_leap_idx].ls_trans)
|
||||
{
|
||||
/* we are at leap point */
|
||||
cur_corr= sp->lsis[next_leap_idx].ls_corr;
|
||||
++next_leap_idx;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if we have had enough space */
|
||||
if (sp->revcnt == TZ_MAX_REV_RANGES - 1)
|
||||
return 1;
|
||||
|
||||
/* set maximum end_l as finisher */
|
||||
revts[sp->revcnt]= end_l;
|
||||
|
||||
/* Allocate arrays of proper size in sp and copy result there */
|
||||
if (!(sp->revts= (my_time_t *)alloc_root(storage,
|
||||
sizeof(my_time_t) * (sp->revcnt + 1))) ||
|
||||
!(sp->revtis= (REVT_INFO *)alloc_root(storage,
|
||||
sizeof(REVT_INFO) * sp->revcnt)))
|
||||
return 1;
|
||||
|
||||
memcpy(sp->revts, revts, sizeof(my_time_t) * (sp->revcnt + 1));
|
||||
memcpy(sp->revtis, revtis, sizeof(REVT_INFO) * sp->revcnt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TIME_ZONE_INFO* tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
|
||||
{
|
||||
TABLE *table= 0;
|
||||
TIME_ZONE_INFO *tz_info= NULL;
|
||||
//Tz_names_entry *tmp_tzname;
|
||||
TIME_ZONE_INFO *return_val= 0;
|
||||
int res;
|
||||
uint tzid, ttid;
|
||||
my_time_t ttime;
|
||||
char buff[MAX_FIELD_WIDTH];
|
||||
uchar keybuff[32];
|
||||
Field *field;
|
||||
String abbr(buff, sizeof(buff), &my_charset_latin1);
|
||||
char *alloc_buff= NULL;
|
||||
char *tz_name_buff= NULL;
|
||||
/*
|
||||
Temporary arrays that are used for loading of data for filling
|
||||
TIME_ZONE_INFO structure
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
TIME_ZONE_INFO tmp_tz_info;
|
||||
memset(&tmp_tz_info, 0, sizeof(TIME_ZONE_INFO));
|
||||
|
||||
DBUG_ENTER("tz_load_from_open_tables");
|
||||
|
||||
/*
|
||||
Let us find out time zone id by its name (there is only one index
|
||||
and it is specifically for this purpose).
|
||||
*/
|
||||
table= tz_tables->table;
|
||||
tz_tables= tz_tables->next_local;
|
||||
table->field[0]->store(tz_name->ptr(), tz_name->length(),
|
||||
&my_charset_latin1);
|
||||
if (table->file->ha_index_init(0, 1))
|
||||
goto end;
|
||||
|
||||
if (table->file->ha_index_read_map(table->record[0], table->field[0]->ptr,
|
||||
HA_WHOLE_KEY, HA_READ_KEY_EXACT))
|
||||
{
|
||||
#ifdef EXTRA_DEBUG
|
||||
/*
|
||||
Most probably user has mistyped time zone name, so no need to bark here
|
||||
unless we need it for debugging.
|
||||
*/
|
||||
sql_print_error("Can't find description of time zone '%.*b'",
|
||||
tz_name->length(), tz_name->ptr());
|
||||
#endif
|
||||
goto end;
|
||||
}
|
||||
|
||||
tzid= (uint)table->field[1]->val_int();
|
||||
|
||||
(void)table->file->ha_index_end();
|
||||
|
||||
/*
|
||||
Now we need to lookup record in mysql.time_zone table in order to
|
||||
understand whenever this timezone uses leap seconds (again we are
|
||||
using the only index in this table).
|
||||
*/
|
||||
table= tz_tables->table;
|
||||
tz_tables= tz_tables->next_local;
|
||||
field= table->field[0];
|
||||
field->store((longlong) tzid, true);
|
||||
DBUG_ASSERT(field->key_length() <= sizeof(keybuff));
|
||||
field->get_key_image(keybuff,
|
||||
MY_MIN(field->key_length(), sizeof(keybuff)),
|
||||
Field::itRAW);
|
||||
if (table->file->ha_index_init(0, 1))
|
||||
goto end;
|
||||
|
||||
if (table->file->ha_index_read_map(table->record[0], keybuff,
|
||||
HA_WHOLE_KEY, HA_READ_KEY_EXACT))
|
||||
{
|
||||
sql_print_error("Can't find description of time zone '%u'", tzid);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* If Uses_leap_seconds == 'Y' */
|
||||
if (table->field[1]->val_int() == 1)
|
||||
{
|
||||
tmp_tz_info.leapcnt= tz_leapcnt;
|
||||
tmp_tz_info.lsis= tz_lsis;
|
||||
}
|
||||
|
||||
(void)table->file->ha_index_end();
|
||||
|
||||
/*
|
||||
Now we will iterate through records for out time zone in
|
||||
mysql.time_zone_transition_type table. Because we want records
|
||||
only for our time zone guess what are we doing?
|
||||
Right - using special index.
|
||||
*/
|
||||
table= tz_tables->table;
|
||||
tz_tables= tz_tables->next_local;
|
||||
field= table->field[0];
|
||||
field->store((longlong) tzid, true);
|
||||
DBUG_ASSERT(field->key_length() <= sizeof(keybuff));
|
||||
field->get_key_image(keybuff,
|
||||
MY_MIN(field->key_length(), sizeof(keybuff)),
|
||||
Field::itRAW);
|
||||
if (table->file->ha_index_init(0, 1))
|
||||
goto end;
|
||||
|
||||
res= table->file->ha_index_read_map(table->record[0], keybuff,
|
||||
(key_part_map)1, HA_READ_KEY_EXACT);
|
||||
while (!res)
|
||||
{
|
||||
ttid= (uint)table->field[1]->val_int();
|
||||
|
||||
if (ttid >= TZ_MAX_TYPES)
|
||||
{
|
||||
sql_print_error("Error while loading time zone description from "
|
||||
"mysql.time_zone_transition_type table: too big "
|
||||
"transition type id");
|
||||
goto end;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
sql_print_error("Error while loading time zone description from "
|
||||
"mysql.time_zone_transition_type table: not enough "
|
||||
"room for abbreviations");
|
||||
goto end;
|
||||
}
|
||||
ttis[ttid].tt_abbrind= tmp_tz_info.charcnt;
|
||||
memcpy(chars + tmp_tz_info.charcnt, abbr.ptr(), abbr.length());
|
||||
tmp_tz_info.charcnt+= abbr.length();
|
||||
chars[tmp_tz_info.charcnt]= 0;
|
||||
tmp_tz_info.charcnt++;
|
||||
|
||||
DBUG_PRINT("info",("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 */
|
||||
DBUG_ASSERT(ttid >= tmp_tz_info.typecnt);
|
||||
|
||||
tmp_tz_info.typecnt= ttid + 1;
|
||||
|
||||
res= table->file->ha_index_next_same(table->record[0], keybuff, 4);
|
||||
}
|
||||
|
||||
if (res != HA_ERR_END_OF_FILE)
|
||||
{
|
||||
sql_print_error("Error while loading time zone description from "
|
||||
"mysql.time_zone_transition_type table");
|
||||
goto end;
|
||||
}
|
||||
|
||||
(void)table->file->ha_index_end();
|
||||
|
||||
|
||||
/*
|
||||
At last we are doing the same thing for records in
|
||||
mysql.time_zone_transition table. Here we additionally need records
|
||||
in ascending order by index scan also satisfies us.
|
||||
*/
|
||||
table= tz_tables->table;
|
||||
table->field[0]->store((longlong) tzid, true);
|
||||
if (table->file->ha_index_init(0, 1))
|
||||
goto end;
|
||||
|
||||
res= table->file->ha_index_read_map(table->record[0], keybuff,
|
||||
(key_part_map)1, HA_READ_KEY_EXACT);
|
||||
while (!res)
|
||||
{
|
||||
ttime= (my_time_t)table->field[1]->val_int();
|
||||
ttid= (uint)table->field[2]->val_int();
|
||||
|
||||
if (tmp_tz_info.timecnt + 1 > TZ_MAX_TIMES)
|
||||
{
|
||||
sql_print_error("Error while loading time zone description from "
|
||||
"mysql.time_zone_transition table: "
|
||||
"too much transitions");
|
||||
goto end;
|
||||
}
|
||||
if (ttid + 1 > tmp_tz_info.typecnt)
|
||||
{
|
||||
sql_print_error("Error while loading time zone description from "
|
||||
"mysql.time_zone_transition table: "
|
||||
"bad transition type id");
|
||||
goto end;
|
||||
}
|
||||
|
||||
ats[tmp_tz_info.timecnt]= ttime;
|
||||
types[tmp_tz_info.timecnt]= ttid;
|
||||
tmp_tz_info.timecnt++;
|
||||
|
||||
DBUG_PRINT("info", ("time_zone_transition table: tz_id: %u tt_time: %lu tt_id: %u",
|
||||
tzid, (ulong) ttime, ttid));
|
||||
|
||||
res= table->file->ha_index_next_same(table->record[0], keybuff, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
We have to allow HA_ERR_KEY_NOT_FOUND because some time zones
|
||||
for example UTC have no transitons.
|
||||
*/
|
||||
if (res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
|
||||
{
|
||||
sql_print_error("Error while loading time zone description from "
|
||||
"mysql.time_zone_transition table");
|
||||
goto end;
|
||||
}
|
||||
|
||||
(void)table->file->ha_index_end();
|
||||
table= 0;
|
||||
|
||||
/*
|
||||
Let us check how correct our time zone description is. We don't check for
|
||||
tz->timecnt < 1 since it is ok for GMT.
|
||||
*/
|
||||
if (tmp_tz_info.typecnt < 1)
|
||||
{
|
||||
sql_print_error("loading time zone without transition types");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Allocate memory for the timezone info and timezone name in tz_storage. */
|
||||
if (!(alloc_buff= (char*) alloc_root(&tz_storage, sizeof(TIME_ZONE_INFO) + tz_name->length() + 1)))
|
||||
{
|
||||
sql_print_error("Out of memory while loading time zone description");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move the temporary tz_info into the allocated area */
|
||||
tz_info= (TIME_ZONE_INFO *)alloc_buff;
|
||||
memcpy(tz_info, &tmp_tz_info, sizeof(TIME_ZONE_INFO));
|
||||
tz_name_buff= alloc_buff + sizeof(TIME_ZONE_INFO);
|
||||
/*
|
||||
By writing zero to the end we guarantee that we can call ptr()
|
||||
instead of c_ptr() for time zone name.
|
||||
*/
|
||||
strmake(tz_name_buff, tz_name->ptr(), tz_name->length());
|
||||
|
||||
/*
|
||||
Now we will allocate memory and init TIME_ZONE_INFO structure.
|
||||
*/
|
||||
if (!(alloc_buff= (char*) alloc_root(&tz_storage,
|
||||
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)))
|
||||
{
|
||||
sql_print_error("Out of memory while loading time zone description");
|
||||
goto end;
|
||||
}
|
||||
|
||||
tz_info->ats= (my_time_t *) alloc_buff;
|
||||
memcpy(tz_info->ats, ats, tz_info->timecnt * sizeof(my_time_t));
|
||||
alloc_buff+= ALIGN_SIZE(sizeof(my_time_t) * tz_info->timecnt);
|
||||
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));
|
||||
|
||||
/* Build reversed map. */
|
||||
if (prepare_tz_info(tz_info, &tz_storage))
|
||||
{
|
||||
sql_print_error("Unable to build mktime map for time zone");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
Loading of time zone succeeded
|
||||
*/
|
||||
return_val= tz_info;
|
||||
|
||||
end:
|
||||
|
||||
if (table && table->file->inited)
|
||||
(void) table->file->ha_index_end();
|
||||
|
||||
DBUG_RETURN(return_val);
|
||||
}
|
||||
|
||||
TIME_ZONE_INFO* my_tzinfo_find(THD *thd, const String *name)
|
||||
{
|
||||
TIME_ZONE_INFO* result_tzinfo= 0;
|
||||
long offset;
|
||||
DBUG_ENTER("my_tz_find");
|
||||
DBUG_PRINT("enter", ("time zone name='%s'\n",
|
||||
name ? ((String *)name)->c_ptr_safe() : "NULL"));
|
||||
|
||||
if (!name || name->is_empty())
|
||||
DBUG_RETURN(0);
|
||||
|
||||
if (!timeZoneToOffset(name->ptr(), name->length(), &offset))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
result_tzinfo= 0;
|
||||
my_tz_init(thd,NULL, 0);
|
||||
if (time_zone_tables_exist)
|
||||
{
|
||||
TABLE_LIST tz_tables[MY_TZ_TABLES_COUNT];
|
||||
|
||||
/*
|
||||
Allocate start_new_trans with malloc as it's > 4000 bytes and this
|
||||
function can be called deep inside a stored procedure
|
||||
*/
|
||||
start_new_trans *new_trans= new start_new_trans(thd);
|
||||
tz_init_table_list(tz_tables);
|
||||
init_mdl_requests(tz_tables);
|
||||
if (!open_system_tables_for_read(thd, tz_tables))
|
||||
{
|
||||
result_tzinfo= tz_load_from_open_tables(name, tz_tables);
|
||||
thd->commit_whole_transaction_and_close_tables();
|
||||
}
|
||||
new_trans->restore_old_transaction();
|
||||
delete new_trans;
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_RETURN(result_tzinfo);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user