You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-11-03 17:13:17 +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
 |