You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-10-31 18:30:33 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			577 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			577 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* 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
 | |
| #pragma GCC diagnostic push
 | |
| #pragma GCC diagnostic ignored "-Wunused-parameter"
 | |
| #include <sql_base.h>
 | |
| #pragma GCC diagnostic pop
 | |
| 
 | |
| // 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);
 | |
| }
 | |
| 
 | |
| }  // namespace cal_impl_if
 |