136
static my_bool prepare_tz_info(TIME_ZONE_INFO *sp, MEM_ROOT *storage);
139
#if defined(TZINFO2SQL) || defined(TESTTIME)
142
Load time zone description from zoneinfo (TZinfo) file.
146
name - path to zoneinfo file
147
sp - TIME_ZONE_INFO structure to fill
154
tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
161
if (!(file= my_fopen(name, O_RDONLY|O_BINARY, MYF(MY_WME))))
166
struct tzhead tzhead;
167
uchar buf[sizeof(struct tzhead) + sizeof(my_time_t) * TZ_MAX_TIMES +
168
TZ_MAX_TIMES + sizeof(TRAN_TYPE_INFO) * TZ_MAX_TYPES +
170
max(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1))) +
172
sizeof(LS_INFO) * TZ_MAX_LEAPS];
178
read_from_file= my_fread(file, u.buf, sizeof(u.buf), MYF(MY_WME));
180
if (my_fclose(file, MYF(MY_WME)) != 0)
183
if (read_from_file < (int)sizeof(struct tzhead))
186
ttisstdcnt= int4net(u.tzhead.tzh_ttisgmtcnt);
187
ttisgmtcnt= int4net(u.tzhead.tzh_ttisstdcnt);
188
sp->leapcnt= int4net(u.tzhead.tzh_leapcnt);
189
sp->timecnt= int4net(u.tzhead.tzh_timecnt);
190
sp->typecnt= int4net(u.tzhead.tzh_typecnt);
191
sp->charcnt= int4net(u.tzhead.tzh_charcnt);
192
p= u.tzhead.tzh_charcnt + sizeof(u.tzhead.tzh_charcnt);
193
if (sp->leapcnt > TZ_MAX_LEAPS ||
194
sp->typecnt == 0 || sp->typecnt > TZ_MAX_TYPES ||
195
sp->timecnt > TZ_MAX_TIMES ||
196
sp->charcnt > TZ_MAX_CHARS ||
197
(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
198
(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
200
if ((uint)(read_from_file - (p - u.buf)) <
201
sp->timecnt * 4 + /* ats */
202
sp->timecnt + /* types */
203
sp->typecnt * (4 + 2) + /* ttinfos */
204
sp->charcnt + /* chars */
205
sp->leapcnt * (4 + 4) + /* lsinfos */
206
ttisstdcnt + /* ttisstds */
207
ttisgmtcnt) /* ttisgmts */
210
if (!(tzinfo_buf= (char *)alloc_root(storage,
211
ALIGN_SIZE(sp->timecnt *
213
ALIGN_SIZE(sp->timecnt) +
214
ALIGN_SIZE(sp->typecnt *
215
sizeof(TRAN_TYPE_INFO)) +
217
ALIGN_SIZE(sp->charcnt) +
219
sp->leapcnt * sizeof(LS_INFO))))
222
sp->ats= (my_time_t *)tzinfo_buf;
223
tzinfo_buf+= ALIGN_SIZE(sp->timecnt * sizeof(my_time_t));
224
sp->types= (uchar *)tzinfo_buf;
225
tzinfo_buf+= ALIGN_SIZE(sp->timecnt);
226
sp->ttis= (TRAN_TYPE_INFO *)tzinfo_buf;
227
tzinfo_buf+= ALIGN_SIZE(sp->typecnt * sizeof(TRAN_TYPE_INFO));
229
sp->chars= tzinfo_buf;
230
tzinfo_buf+= ALIGN_SIZE(sp->charcnt);
232
sp->lsis= (LS_INFO *)tzinfo_buf;
234
for (i= 0; i < sp->timecnt; i++, p+= 4)
235
sp->ats[i]= int4net(p);
237
for (i= 0; i < sp->timecnt; i++)
239
sp->types[i]= (uchar) *p++;
240
if (sp->types[i] >= sp->typecnt)
243
for (i= 0; i < sp->typecnt; i++)
245
TRAN_TYPE_INFO * ttisp;
248
ttisp->tt_gmtoff= int4net(p);
250
ttisp->tt_isdst= (uchar) *p++;
251
if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
253
ttisp->tt_abbrind= (uchar) *p++;
254
if (ttisp->tt_abbrind > sp->charcnt)
257
for (i= 0; i < sp->charcnt; i++)
259
sp->chars[i]= '\0'; /* ensure '\0' at end */
260
for (i= 0; i < sp->leapcnt; i++)
265
lsisp->ls_trans= int4net(p);
267
lsisp->ls_corr= int4net(p);
271
Since we don't support POSIX style TZ definitions in variables we
272
don't read further like glibc or elsie code.
276
return prepare_tz_info(sp, storage);
278
#endif /* defined(TZINFO2SQL) || defined(TESTTIME) */
282
Finish preparation of time zone description for use in TIME_to_gmt_sec()
283
and gmt_sec_to_TIME() functions.
287
sp - pointer to time zone description
288
storage - pointer to MEM_ROOT where arrays for map allocated
291
First task of this function is to find fallback time type which will
292
be used if there are no transitions or we have moment in time before
294
Second task is to build "shifted my_time_t" -> my_time_t map used in
295
MYSQL_TIME -> my_time_t conversion.
296
Note: See description of TIME_to_gmt_sec() function first.
297
In order to perform MYSQL_TIME -> my_time_t conversion we need to build table
298
which defines "shifted by tz offset and leap seconds my_time_t" ->
299
my_time_t function wich is almost the same (except ranges of ambiguity)
300
as reverse function to piecewise linear function used for my_time_t ->
301
"shifted my_time_t" conversion and which is also specified as table in
302
zoneinfo file or in our db (It is specified as start of time type ranges
303
and time type offsets). So basic idea is very simple - let us iterate
304
through my_time_t space from one point of discontinuity of my_time_t ->
305
"shifted my_time_t" function to another and build our approximation of
306
reverse function. (Actually we iterate through ranges on which
307
my_time_t -> "shifted my_time_t" is linear function).
314
prepare_tz_info(TIME_ZONE_INFO *sp, MEM_ROOT *storage)
316
my_time_t cur_t= MY_TIME_T_MIN;
317
my_time_t cur_l, end_t, end_l;
318
my_time_t cur_max_seen_l= MY_TIME_T_MIN;
319
long cur_offset, cur_corr, cur_off_and_corr;
320
uint next_trans_idx, next_leap_idx;
323
Temporary arrays where we will store tables. Needed because
324
we don't know table sizes ahead. (Well we can estimate their
325
upper bound but this will take extra space.)
327
my_time_t revts[TZ_MAX_REV_RANGES];
328
REVT_INFO revtis[TZ_MAX_REV_RANGES];
331
Let us setup fallback time type which will be used if we have not any
332
transitions or if we have moment of time before first transition.
333
We will find first non-DST local time type and use it (or use first
334
local time type if all of them are DST types).
336
for (i= 0; i < sp->typecnt && sp->ttis[i].tt_isdst; i++)
338
if (i == sp->typecnt)
340
sp->fallback_tti= &(sp->ttis[i]);
344
Let us build shifted my_time_t -> my_time_t map.
348
/* Let us find initial offset */
349
if (sp->timecnt == 0 || cur_t < sp->ats[0])
352
If we have not any transitions or t is before first transition we are using
353
already found fallback time type which index is already in i.
359
/* cur_t == sp->ats[0] so we found transition */
364
cur_offset= sp->ttis[i].tt_gmtoff;
367
/* let us find leap correction... unprobable, but... */
368
for (next_leap_idx= 0; next_leap_idx < sp->leapcnt &&
369
cur_t >= sp->lsis[next_leap_idx].ls_trans;
373
if (next_leap_idx > 0)
374
cur_corr= sp->lsis[next_leap_idx - 1].ls_corr;
378
/* Iterate trough t space */
379
while (sp->revcnt < TZ_MAX_REV_RANGES - 1)
381
cur_off_and_corr= cur_offset - cur_corr;
384
We assuming that cur_t could be only overflowed downwards,
385
we also assume that end_t won't be overflowed in this case.
387
if (cur_off_and_corr < 0 &&
388
cur_t < MY_TIME_T_MIN - cur_off_and_corr)
389
cur_t= MY_TIME_T_MIN - cur_off_and_corr;
391
cur_l= cur_t + cur_off_and_corr;
394
Let us choose end_t as point before next time type change or leap
397
end_t= min((next_trans_idx < sp->timecnt) ? sp->ats[next_trans_idx] - 1:
399
(next_leap_idx < sp->leapcnt) ?
400
sp->lsis[next_leap_idx].ls_trans - 1: MY_TIME_T_MAX);
402
again assuming that end_t can be overlowed only in positive side
403
we also assume that end_t won't be overflowed in this case.
405
if (cur_off_and_corr > 0 &&
406
end_t > MY_TIME_T_MAX - cur_off_and_corr)
407
end_t= MY_TIME_T_MAX - cur_off_and_corr;
409
end_l= end_t + cur_off_and_corr;
412
if (end_l > cur_max_seen_l)
414
/* We want special handling in the case of first range */
415
if (cur_max_seen_l == MY_TIME_T_MIN)
417
revts[sp->revcnt]= cur_l;
418
revtis[sp->revcnt].rt_offset= cur_off_and_corr;
419
revtis[sp->revcnt].rt_type= 0;
421
cur_max_seen_l= end_l;
425
if (cur_l > cur_max_seen_l + 1)
427
/* We have a spring time-gap and we are not at the first range */
428
revts[sp->revcnt]= cur_max_seen_l + 1;
429
revtis[sp->revcnt].rt_offset= revtis[sp->revcnt-1].rt_offset;
430
revtis[sp->revcnt].rt_type= 1;
432
if (sp->revcnt == TZ_MAX_TIMES + TZ_MAX_LEAPS + 1)
433
break; /* That was too much */
434
cur_max_seen_l= cur_l - 1;
437
/* Assume here end_l > cur_max_seen_l (because end_l>=cur_l) */
439
revts[sp->revcnt]= cur_max_seen_l + 1;
440
revtis[sp->revcnt].rt_offset= cur_off_and_corr;
441
revtis[sp->revcnt].rt_type= 0;
443
cur_max_seen_l= end_l;
447
if (end_t == MY_TIME_T_MAX ||
448
((cur_off_and_corr > 0) && (end_t >= MY_TIME_T_MAX - cur_off_and_corr)))
455
Let us find new offset and correction. Because of our choice of end_t
456
cur_t can only be point where new time type starts or/and leap
457
correction is performed.
459
if (sp->timecnt != 0 && cur_t >= sp->ats[0]) /* else reuse old offset */
460
if (next_trans_idx < sp->timecnt &&
461
cur_t == sp->ats[next_trans_idx])
463
/* We are at offset point */
464
cur_offset= sp->ttis[sp->types[next_trans_idx]].tt_gmtoff;
468
if (next_leap_idx < sp->leapcnt &&
469
cur_t == sp->lsis[next_leap_idx].ls_trans)
471
/* we are at leap point */
472
cur_corr= sp->lsis[next_leap_idx].ls_corr;
477
/* check if we have had enough space */
478
if (sp->revcnt == TZ_MAX_REV_RANGES - 1)
481
/* set maximum end_l as finisher */
482
revts[sp->revcnt]= end_l;
484
/* Allocate arrays of proper size in sp and copy result there */
485
if (!(sp->revts= (my_time_t *)alloc_root(storage,
486
sizeof(my_time_t) * (sp->revcnt + 1))) ||
487
!(sp->revtis= (REVT_INFO *)alloc_root(storage,
488
sizeof(REVT_INFO) * sp->revcnt)))
491
memcpy(sp->revts, revts, sizeof(my_time_t) * (sp->revcnt + 1));
492
memcpy(sp->revtis, revtis, sizeof(REVT_INFO) * sp->revcnt);
498
102
#if !defined(TZINFO2SQL)
500
104
static const uint mon_lengths[2][MONS_PER_YEAR]=
1556
my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
1054
my_tz_init(THD *thd, const char *default_tzname, my_bool bootstrap)
1559
TABLE_LIST tz_tables[1+MY_TZ_TABLES_COUNT];
1560
Open_tables_state open_tables_state_backup;
1562
Tz_names_entry *tmp_tzname;
1563
my_bool return_val= 1;
1566
DBUG_ENTER("my_tz_init");
1569
To be able to run this from boot, we allocate a temporary THD
1571
if (!(thd= new THD))
1573
thd->thread_stack= (char*) &thd;
1574
thd->store_globals();
1577
/* Init all memory structures that require explicit destruction */
1578
if (hash_init(&tz_names, &my_charset_latin1, 20,
1579
0, 0, (hash_get_key) my_tz_names_get_key, 0, 0))
1581
sql_print_error("Fatal error: OOM while initializing time zones");
1584
if (hash_init(&offset_tzs, &my_charset_latin1, 26, 0, 0,
1585
(hash_get_key)my_offset_tzs_get_key, 0, 0))
1587
sql_print_error("Fatal error: OOM while initializing time zones");
1588
hash_free(&tz_names);
1591
init_sql_alloc(&tz_storage, 32 * 1024, 0);
1592
VOID(pthread_mutex_init(&tz_LOCK, MY_MUTEX_INIT_FAST));
1595
/* Add 'SYSTEM' time zone to tz_names hash */
1596
if (!(tmp_tzname= new (&tz_storage) Tz_names_entry()))
1598
sql_print_error("Fatal error: OOM while initializing time zones");
1599
goto end_with_cleanup;
1601
tmp_tzname->name.set(STRING_WITH_LEN("SYSTEM"), &my_charset_latin1);
1602
tmp_tzname->tz= my_tz_SYSTEM;
1603
if (my_hash_insert(&tz_names, (const uchar *)tmp_tzname))
1605
sql_print_error("Fatal error: OOM while initializing time zones");
1606
goto end_with_cleanup;
1611
/* If we are in bootstrap mode we should not load time zone tables */
1612
return_val= time_zone_tables_exist= 0;
1613
goto end_with_setting_default_tz;
1617
After this point all memory structures are inited and we even can live
1618
without time zone description tables. Now try to load information about
1619
leap seconds shared by all time zones.
1622
thd->set_db(db, sizeof(db)-1);
1623
bzero((char*) &tz_tables[0], sizeof(TABLE_LIST));
1624
tz_tables[0].alias= tz_tables[0].table_name=
1625
(char*)"time_zone_leap_second";
1626
tz_tables[0].table_name_length= 21;
1627
tz_tables[0].db= db;
1628
tz_tables[0].db_length= sizeof(db)-1;
1629
tz_tables[0].lock_type= TL_READ;
1631
tz_init_table_list(tz_tables+1);
1632
tz_tables[0].next_global= tz_tables[0].next_local= &tz_tables[1];
1633
tz_tables[1].prev_global= &tz_tables[0].next_global;
1636
We need to open only mysql.time_zone_leap_second, but we try to
1637
open all time zone tables to see if they exist.
1639
if (open_system_tables_for_read(thd, tz_tables, &open_tables_state_backup))
1641
sql_print_warning("Can't open and lock time zone table: %s "
1642
"trying to live without them", thd->main_da.message());
1643
/* We will try emulate that everything is ok */
1644
return_val= time_zone_tables_exist= 0;
1645
goto end_with_setting_default_tz;
1649
Now we are going to load leap seconds descriptions that are shared
1650
between all time zones that use them. We are using index for getting
1651
records in proper order. Since we share the same MEM_ROOT between
1652
all time zones we just allocate enough memory for it first.
1654
if (!(tz_lsis= (LS_INFO*) alloc_root(&tz_storage,
1655
sizeof(LS_INFO) * TZ_MAX_LEAPS)))
1657
sql_print_error("Fatal error: Out of memory while loading "
1658
"mysql.time_zone_leap_second table");
1659
goto end_with_close;
1662
table= tz_tables[0].table;
1664
It is OK to ignore ha_index_init()/ha_index_end() return values since
1665
mysql.time_zone* tables are MyISAM and these operations always succeed
1668
(void)table->file->ha_index_init(0, 1);
1669
table->use_all_columns();
1673
res= table->file->index_first(table->record[0]);
1677
if (tz_leapcnt + 1 > TZ_MAX_LEAPS)
1679
sql_print_error("Fatal error: While loading mysql.time_zone_leap_second"
1680
" table: too much leaps");
1681
table->file->ha_index_end();
1682
goto end_with_close;
1685
tz_lsis[tz_leapcnt].ls_trans= (my_time_t)table->field[0]->val_int();
1686
tz_lsis[tz_leapcnt].ls_corr= (long)table->field[1]->val_int();
1691
("time_zone_leap_second table: tz_leapcnt: %u tt_time: %lu offset: %ld",
1692
tz_leapcnt, (ulong) tz_lsis[tz_leapcnt-1].ls_trans,
1693
tz_lsis[tz_leapcnt-1].ls_corr));
1695
res= table->file->index_next(table->record[0]);
1698
(void)table->file->ha_index_end();
1700
if (res != HA_ERR_END_OF_FILE)
1702
sql_print_error("Fatal error: Error while loading "
1703
"mysql.time_zone_leap_second table");
1704
goto end_with_close;
1708
Loading of info about leap seconds succeeded
1714
end_with_setting_default_tz:
1715
/* If we have default time zone try to load it */
1716
1056
if (default_tzname)
1718
1058
String tmp_tzname2(default_tzname, &my_charset_latin1);
1726
1066
sql_print_error("Fatal error: Illegal or unknown default time zone '%s'",
1727
1067
default_tzname);
1733
if (time_zone_tables_exist)
1735
thd->version--; /* Force close to free memory */
1736
close_system_tables(thd, &open_tables_state_backup);
1741
/* if there were error free time zone describing structs */
1747
org_thd->store_globals(); /* purecov: inspected */
1750
/* Remember that we don't have a THD */
1751
my_pthread_setspecific_ptr(THR_THD, 0);
1752
my_pthread_setspecific_ptr(THR_MALLOC, 0);
1754
DBUG_RETURN(return_val);
1759
1077
Free resources used by time zone support infrastructure.
1765
1080
void my_tz_free()
1770
VOID(pthread_mutex_destroy(&tz_LOCK));
1771
hash_free(&offset_tzs);
1772
hash_free(&tz_names);
1773
free_root(&tz_storage, MYF(0));
1779
Load time zone description from system tables.
1782
tz_load_from_open_tables()
1783
tz_name - name of time zone that should be loaded.
1784
tz_tables - list of tables from which time zone description
1788
This function will try to load information about time zone specified
1789
from the list of the already opened and locked tables (first table in
1790
tz_tables should be time_zone_name, next time_zone, then
1791
time_zone_transition_type and time_zone_transition should be last).
1792
It will also update information in hash used for time zones lookup.
1795
Returns pointer to newly created Time_zone object or 0 in case of error.
1800
tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
1803
TIME_ZONE_INFO *tz_info;
1804
Tz_names_entry *tmp_tzname;
1805
Time_zone *return_val= 0;
1809
char buff[MAX_FIELD_WIDTH];
1810
String abbr(buff, sizeof(buff), &my_charset_latin1);
1811
char *alloc_buff, *tz_name_buff;
1813
Temporary arrays that are used for loading of data for filling
1814
TIME_ZONE_INFO structure
1816
my_time_t ats[TZ_MAX_TIMES];
1817
uchar types[TZ_MAX_TIMES];
1818
TRAN_TYPE_INFO ttis[TZ_MAX_TYPES];
1819
#ifdef ABBR_ARE_USED
1820
char chars[max(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1)))];
1822
DBUG_ENTER("tz_load_from_open_tables");
1824
/* Prepare tz_info for loading also let us make copy of time zone name */
1825
if (!(alloc_buff= (char*) alloc_root(&tz_storage, sizeof(TIME_ZONE_INFO) +
1826
tz_name->length() + 1)))
1828
sql_print_error("Out of memory while loading time zone description");
1831
tz_info= (TIME_ZONE_INFO *)alloc_buff;
1832
bzero(tz_info, sizeof(TIME_ZONE_INFO));
1833
tz_name_buff= alloc_buff + sizeof(TIME_ZONE_INFO);
1835
By writing zero to the end we guarantee that we can call ptr()
1836
instead of c_ptr() for time zone name.
1838
strmake(tz_name_buff, tz_name->ptr(), tz_name->length());
1841
Let us find out time zone id by its name (there is only one index
1842
and it is specifically for this purpose).
1844
table= tz_tables->table;
1845
tz_tables= tz_tables->next_local;
1846
table->field[0]->store(tz_name->ptr(), tz_name->length(),
1847
&my_charset_latin1);
1849
It is OK to ignore ha_index_init()/ha_index_end() return values since
1850
mysql.time_zone* tables are MyISAM and these operations always succeed
1853
(void)table->file->ha_index_init(0, 1);
1855
if (table->file->index_read_map(table->record[0], table->field[0]->ptr,
1856
HA_WHOLE_KEY, HA_READ_KEY_EXACT))
1860
Most probably user has mistyped time zone name, so no need to bark here
1861
unless we need it for debugging.
1863
sql_print_error("Can't find description of time zone '%s'", tz_name_buff);
1868
tzid= (uint)table->field[1]->val_int();
1870
(void)table->file->ha_index_end();
1873
Now we need to lookup record in mysql.time_zone table in order to
1874
understand whenever this timezone uses leap seconds (again we are
1875
using the only index in this table).
1877
table= tz_tables->table;
1878
tz_tables= tz_tables->next_local;
1879
table->field[0]->store((longlong) tzid, TRUE);
1880
(void)table->file->ha_index_init(0, 1);
1882
if (table->file->index_read_map(table->record[0], table->field[0]->ptr,
1883
HA_WHOLE_KEY, HA_READ_KEY_EXACT))
1885
sql_print_error("Can't find description of time zone '%u'", tzid);
1889
/* If Uses_leap_seconds == 'Y' */
1890
if (table->field[1]->val_int() == 1)
1892
tz_info->leapcnt= tz_leapcnt;
1893
tz_info->lsis= tz_lsis;
1896
(void)table->file->ha_index_end();
1899
Now we will iterate through records for out time zone in
1900
mysql.time_zone_transition_type table. Because we want records
1901
only for our time zone guess what are we doing?
1902
Right - using special index.
1904
table= tz_tables->table;
1905
tz_tables= tz_tables->next_local;
1906
table->field[0]->store((longlong) tzid, TRUE);
1907
(void)table->file->ha_index_init(0, 1);
1909
res= table->file->index_read_map(table->record[0], table->field[0]->ptr,
1910
(key_part_map)1, HA_READ_KEY_EXACT);
1913
ttid= (uint)table->field[1]->val_int();
1915
if (ttid >= TZ_MAX_TYPES)
1917
sql_print_error("Error while loading time zone description from "
1918
"mysql.time_zone_transition_type table: too big "
1919
"transition type id");
1923
ttis[ttid].tt_gmtoff= (long)table->field[2]->val_int();
1924
ttis[ttid].tt_isdst= (table->field[3]->val_int() > 0);
1926
#ifdef ABBR_ARE_USED
1927
// FIXME should we do something with duplicates here ?
1928
table->field[4]->val_str(&abbr, &abbr);
1929
if (tz_info->charcnt + abbr.length() + 1 > sizeof(chars))
1931
sql_print_error("Error while loading time zone description from "
1932
"mysql.time_zone_transition_type table: not enough "
1933
"room for abbreviations");
1936
ttis[ttid].tt_abbrind= tz_info->charcnt;
1937
memcpy(chars + tz_info->charcnt, abbr.ptr(), abbr.length());
1938
tz_info->charcnt+= abbr.length();
1939
chars[tz_info->charcnt]= 0;
1943
("time_zone_transition_type table: tz_id=%u tt_id=%u tt_gmtoff=%ld "
1944
"abbr='%s' tt_isdst=%u", tzid, ttid, ttis[ttid].tt_gmtoff,
1945
chars + ttis[ttid].tt_abbrind, ttis[ttid].tt_isdst));
1948
("time_zone_transition_type table: tz_id=%u tt_id=%u tt_gmtoff=%ld "
1949
"tt_isdst=%u", tzid, ttid, ttis[ttid].tt_gmtoff, ttis[ttid].tt_isdst));
1952
/* ttid is increasing because we are reading using index */
1953
DBUG_ASSERT(ttid >= tz_info->typecnt);
1955
tz_info->typecnt= ttid + 1;
1957
res= table->file->index_next_same(table->record[0],
1958
table->field[0]->ptr, 4);
1961
if (res != HA_ERR_END_OF_FILE)
1963
sql_print_error("Error while loading time zone description from "
1964
"mysql.time_zone_transition_type table");
1968
(void)table->file->ha_index_end();
1972
At last we are doing the same thing for records in
1973
mysql.time_zone_transition table. Here we additionaly need records
1974
in ascending order by index scan also satisfies us.
1976
table= tz_tables->table;
1977
table->field[0]->store((longlong) tzid, TRUE);
1978
(void)table->file->ha_index_init(0, 1);
1980
res= table->file->index_read_map(table->record[0], table->field[0]->ptr,
1981
(key_part_map)1, HA_READ_KEY_EXACT);
1984
ttime= (my_time_t)table->field[1]->val_int();
1985
ttid= (uint)table->field[2]->val_int();
1987
if (tz_info->timecnt + 1 > TZ_MAX_TIMES)
1989
sql_print_error("Error while loading time zone description from "
1990
"mysql.time_zone_transition table: "
1991
"too much transitions");
1994
if (ttid + 1 > tz_info->typecnt)
1996
sql_print_error("Error while loading time zone description from "
1997
"mysql.time_zone_transition table: "
1998
"bad transition type id");
2002
ats[tz_info->timecnt]= ttime;
2003
types[tz_info->timecnt]= ttid;
2007
("time_zone_transition table: tz_id: %u tt_time: %lu tt_id: %u",
2008
tzid, (ulong) ttime, ttid));
2010
res= table->file->index_next_same(table->record[0],
2011
table->field[0]->ptr, 4);
2015
We have to allow HA_ERR_KEY_NOT_FOUND because some time zones
2016
for example UTC have no transitons.
2018
if (res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
2020
sql_print_error("Error while loading time zone description from "
2021
"mysql.time_zone_transition table");
2025
(void)table->file->ha_index_end();
2029
Now we will allocate memory and init TIME_ZONE_INFO structure.
2031
if (!(alloc_buff= (char*) alloc_root(&tz_storage,
2032
ALIGN_SIZE(sizeof(my_time_t) *
2034
ALIGN_SIZE(tz_info->timecnt) +
2035
#ifdef ABBR_ARE_USED
2036
ALIGN_SIZE(tz_info->charcnt) +
2038
sizeof(TRAN_TYPE_INFO) *
2041
sql_print_error("Out of memory while loading time zone description");
2045
tz_info->ats= (my_time_t *) alloc_buff;
2046
memcpy(tz_info->ats, ats, tz_info->timecnt * sizeof(my_time_t));
2047
alloc_buff+= ALIGN_SIZE(sizeof(my_time_t) * tz_info->timecnt);
2048
tz_info->types= (uchar *)alloc_buff;
2049
memcpy(tz_info->types, types, tz_info->timecnt);
2050
alloc_buff+= ALIGN_SIZE(tz_info->timecnt);
2051
#ifdef ABBR_ARE_USED
2052
tz_info->chars= alloc_buff;
2053
memcpy(tz_info->chars, chars, tz_info->charcnt);
2054
alloc_buff+= ALIGN_SIZE(tz_info->charcnt);
2056
tz_info->ttis= (TRAN_TYPE_INFO *)alloc_buff;
2057
memcpy(tz_info->ttis, ttis, tz_info->typecnt * sizeof(TRAN_TYPE_INFO));
2060
Let us check how correct our time zone description and build
2061
reversed map. We don't check for tz->timecnt < 1 since it ok for GMT.
2063
if (tz_info->typecnt < 1)
2065
sql_print_error("loading time zone without transition types");
2068
if (prepare_tz_info(tz_info, &tz_storage))
2070
sql_print_error("Unable to build mktime map for time zone");
2075
if (!(tmp_tzname= new (&tz_storage) Tz_names_entry()) ||
2076
!(tmp_tzname->tz= new (&tz_storage) Time_zone_db(tz_info,
2077
&(tmp_tzname->name))) ||
2078
(tmp_tzname->name.set(tz_name_buff, tz_name->length(),
2079
&my_charset_latin1),
2080
my_hash_insert(&tz_names, (const uchar *)tmp_tzname)))
2082
sql_print_error("Out of memory while loading time zone");
2087
Loading of time zone succeeded
2089
return_val= tmp_tzname->tz;
2094
(void)table->file->ha_index_end();
2096
DBUG_RETURN(return_val);
2181
1166
Get Time_zone object for specified time zone.
2185
thd - pointer to thread THD structure
2186
name - time zone specification
2189
This function checks if name is one of time zones described in db,
2190
predefined SYSTEM time zone or valid time zone specification as
2191
offset from UTC (In last case it will create proper Time_zone_offset
2192
object if there were not any.). If name is ok it returns corresponding
2195
Clients of this function are not responsible for releasing resources
2196
occupied by returned Time_zone object so they can just forget pointers
2197
to Time_zone object if they are not needed longer.
2199
Other important property of this function: if some Time_zone found once
2200
it will be for sure found later, so this function can also be used for
2201
checking if proper Time_zone object exists (and if there will be error
2202
it will be reported during first call).
2204
If name pointer is 0 then this function returns 0 (this allows to pass 0
2205
values as parameter without additional external check and this property
2206
is used by @@time_zone variable handling code).
2208
It will perform lookup in system tables (mysql.time_zone*),
2209
opening and locking them, and closing afterwards. It won't perform
2210
such lookup if no time zone describing tables were found during
2214
Pointer to corresponding Time_zone object. 0 - in case of bad time zone
2215
specification or other error.
1168
Not implemented yet. This needs to hook into some sort of OS system call.
2219
1172
my_tz_find(THD *thd, const String *name)
2221
Tz_names_entry *tmp_tzname;
2222
Time_zone *result_tz= 0;
2224
DBUG_ENTER("my_tz_find");
2225
DBUG_PRINT("enter", ("time zone name='%s'",
2226
name ? ((String *)name)->c_ptr_safe() : "NULL"));
2231
VOID(pthread_mutex_lock(&tz_LOCK));
2233
if (!str_to_offset(name->ptr(), name->length(), &offset))
2236
if (!(result_tz= (Time_zone_offset *)hash_search(&offset_tzs,
2237
(const uchar *)&offset,
2240
DBUG_PRINT("info", ("Creating new Time_zone_offset object"));
2242
if (!(result_tz= new (&tz_storage) Time_zone_offset(offset)) ||
2243
my_hash_insert(&offset_tzs, (const uchar *) result_tz))
2246
sql_print_error("Fatal error: Out of memory "
2247
"while setting new time zone");
2254
if ((tmp_tzname= (Tz_names_entry *)hash_search(&tz_names,
2255
(const uchar *)name->ptr(),
2257
result_tz= tmp_tzname->tz;
2258
else if (time_zone_tables_exist)
2260
TABLE_LIST tz_tables[MY_TZ_TABLES_COUNT];
2261
Open_tables_state open_tables_state_backup;
2263
tz_init_table_list(tz_tables);
2264
if (!open_system_tables_for_read(thd, tz_tables,
2265
&open_tables_state_backup))
2267
result_tz= tz_load_from_open_tables(name, tz_tables);
2268
close_system_tables(thd, &open_tables_state_backup);
2273
VOID(pthread_mutex_unlock(&tz_LOCK));
2275
DBUG_RETURN(result_tz);
2279
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
2284
This code belongs to mysql_tzinfo_to_sql converter command line utility.
2285
This utility should be used by db admin for populating mysql.time_zone
2291
Print info about time zone described by TIME_ZONE_INFO struct as
2292
SQL statements populating mysql.time_zone* tables.
2296
tz_name - name of time zone
2297
sp - structure describing time zone
2300
print_tz_as_sql(const char* tz_name, const TIME_ZONE_INFO *sp)
2304
/* Here we assume that all time zones have same leap correction tables */
2305
printf("INSERT INTO time_zone (Use_leap_seconds) VALUES ('%s');\n",
2306
sp->leapcnt ? "Y" : "N");
2307
printf("SET @time_zone_id= LAST_INSERT_ID();\n");
2308
printf("INSERT INTO time_zone_name (Name, Time_zone_id) VALUES \
2309
('%s', @time_zone_id);\n", tz_name);
2313
printf("INSERT INTO time_zone_transition \
2314
(Time_zone_id, Transition_time, Transition_type_id) VALUES\n");
2315
for (i= 0; i < sp->timecnt; i++)
2316
printf("%s(@time_zone_id, %ld, %u)\n", (i == 0 ? " " : ","), sp->ats[i],
2317
(uint)sp->types[i]);
2321
printf("INSERT INTO time_zone_transition_type \
2322
(Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES\n");
2324
for (i= 0; i < sp->typecnt; i++)
2325
printf("%s(@time_zone_id, %u, %ld, %d, '%s')\n", (i == 0 ? " " : ","), i,
2326
sp->ttis[i].tt_gmtoff, sp->ttis[i].tt_isdst,
2327
sp->chars + sp->ttis[i].tt_abbrind);
2333
Print info about leap seconds in time zone as SQL statements
2334
populating mysql.time_zone_leap_second table.
2337
print_tz_leaps_as_sql()
2338
sp - structure describing time zone
2341
print_tz_leaps_as_sql(const TIME_ZONE_INFO *sp)
2346
We are assuming that there are only one list of leap seconds
2349
printf("TRUNCATE TABLE time_zone_leap_second;\n");
2353
printf("INSERT INTO time_zone_leap_second \
2354
(Transition_time, Correction) VALUES\n");
2355
for (i= 0; i < sp->leapcnt; i++)
2356
printf("%s(%ld, %ld)\n", (i == 0 ? " " : ","),
2357
sp->lsis[i].ls_trans, sp->lsis[i].ls_corr);
2361
printf("ALTER TABLE time_zone_leap_second ORDER BY Transition_time;\n");
2366
Some variables used as temporary or as parameters
2367
in recursive scan_tz_dir() code.
2369
TIME_ZONE_INFO tz_info;
2370
MEM_ROOT tz_storage;
2371
char fullname[FN_REFLEN + 1];
2372
char *root_name_end;
2376
Recursively scan zoneinfo directory and print all found time zone
2377
descriptions as SQL.
2381
name_end - pointer to end of path to directory to be searched.
2384
This auxiliary recursive function also uses several global
2385
variables as in parameters and for storing temporary values.
2387
fullname - path to directory that should be scanned.
2388
root_name_end - pointer to place in fullname where part with
2389
path to initial directory ends.
2390
current_tz_id - last used time zone id
2393
0 - Ok, 1 - Fatal error
2397
scan_tz_dir(char * name_end)
2403
if (!(cur_dir= my_dir(fullname, MYF(MY_WANT_STAT))))
2406
name_end= strmake(name_end, "/", FN_REFLEN - (name_end - fullname));
2408
for (i= 0; i < cur_dir->number_off_files; i++)
2410
if (cur_dir->dir_entry[i].name[0] != '.')
2412
name_end_tmp= strmake(name_end, cur_dir->dir_entry[i].name,
2413
FN_REFLEN - (name_end - fullname));
2415
if (MY_S_ISDIR(cur_dir->dir_entry[i].mystat->st_mode))
2417
if (scan_tz_dir(name_end_tmp))
2423
else if (MY_S_ISREG(cur_dir->dir_entry[i].mystat->st_mode))
2425
init_alloc_root(&tz_storage, 32768, 0);
2426
if (!tz_load(fullname, &tz_info, &tz_storage))
2427
print_tz_as_sql(root_name_end + 1, &tz_info);
2430
"Warning: Unable to load '%s' as time zone. Skipping it.\n",
2432
free_root(&tz_storage, MYF(0));
2435
fprintf(stderr, "Warning: '%s' is not regular file or directory\n",
2447
main(int argc, char **argv)
2451
if (argc != 2 && argc != 3)
2453
fprintf(stderr, "Usage:\n");
2454
fprintf(stderr, " %s timezonedir\n", argv[0]);
2455
fprintf(stderr, " %s timezonefile timezonename\n", argv[0]);
2456
fprintf(stderr, " %s --leap timezonefile\n", argv[0]);
2462
root_name_end= strmake(fullname, argv[1], FN_REFLEN);
2464
printf("TRUNCATE TABLE time_zone;\n");
2465
printf("TRUNCATE TABLE time_zone_name;\n");
2466
printf("TRUNCATE TABLE time_zone_transition;\n");
2467
printf("TRUNCATE TABLE time_zone_transition_type;\n");
2469
if (scan_tz_dir(root_name_end))
2471
fprintf(stderr, "There were fatal errors during processing "
2472
"of zoneinfo directory\n");
2476
printf("ALTER TABLE time_zone_transition "
2477
"ORDER BY Time_zone_id, Transition_time;\n");
2478
printf("ALTER TABLE time_zone_transition_type "
2479
"ORDER BY Time_zone_id, Transition_type_id;\n");
2483
init_alloc_root(&tz_storage, 32768, 0);
2485
if (strcmp(argv[1], "--leap") == 0)
2487
if (tz_load(argv[2], &tz_info, &tz_storage))
2489
fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[2]);
2492
print_tz_leaps_as_sql(&tz_info);
2496
if (tz_load(argv[1], &tz_info, &tz_storage))
2498
fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[2]);
2501
print_tz_as_sql(argv[2], &tz_info);
2504
free_root(&tz_storage, MYF(0));
2510
#endif /* defined(TZINFO2SQL) */
2516
Some simple brute-force test wich allowed to catch a pair of bugs.
2517
Also can provide interesting facts about system's time zone support
2526
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
2530
#define TYPE_SIGNED(type) (((type) -1) < 0)
2534
is_equal_TIME_tm(const TIME* time_arg, const struct tm * tm_arg)
2536
return (time_arg->year == (uint)tm_arg->tm_year+TM_YEAR_BASE) &&
2537
(time_arg->month == (uint)tm_arg->tm_mon+1) &&
2538
(time_arg->day == (uint)tm_arg->tm_mday) &&
2539
(time_arg->hour == (uint)tm_arg->tm_hour) &&
2540
(time_arg->minute == (uint)tm_arg->tm_min) &&
2541
(time_arg->second == (uint)tm_arg->tm_sec) &&
2542
time_arg->second_part == 0;
2547
main(int argc, char **argv)
2549
my_bool localtime_negative;
2550
TIME_ZONE_INFO tz_info;
2552
MYSQL_TIME time_tmp;
2554
char fullname[FN_REFLEN+1];
2556
MEM_ROOT tz_storage;
2560
init_alloc_root(&tz_storage, 32768, 0);
2562
/* let us set some well known timezone */
2563
setenv("TZ", "MET", 1);
2566
/* Some initial time zone related system info */
2567
printf("time_t: %s %u bit\n", TYPE_SIGNED(time_t) ? "signed" : "unsigned",
2568
(uint)TYPE_BIT(time_t));
2569
if (TYPE_SIGNED(time_t))
2572
localtime_negative= test(localtime_r(&t, &tmp) != 0);
2573
printf("localtime_r %s negative params \
2574
(time_t=%d is %d-%d-%d %d:%d:%d)\n",
2575
(localtime_negative ? "supports" : "doesn't support"), (int)t,
2576
TM_YEAR_BASE + tmp.tm_year, tmp.tm_mon + 1, tmp.tm_mday,
2577
tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
2579
printf("mktime %s negative results (%d)\n",
2580
(t == mktime(&tmp) ? "doesn't support" : "supports"),
2584
tmp.tm_year= 103; tmp.tm_mon= 2; tmp.tm_mday= 30;
2585
tmp.tm_hour= 2; tmp.tm_min= 30; tmp.tm_sec= 0; tmp.tm_isdst= -1;
2587
printf("mktime returns %s for spring time gap (%d)\n",
2588
(t != (time_t)-1 ? "something" : "error"), (int)t);
2590
tmp.tm_year= 103; tmp.tm_mon= 8; tmp.tm_mday= 1;
2591
tmp.tm_hour= 0; tmp.tm_min= 0; tmp.tm_sec= 0; tmp.tm_isdst= 0;
2593
printf("mktime returns %s for non existing date (%d)\n",
2594
(t != (time_t)-1 ? "something" : "error"), (int)t);
2596
tmp.tm_year= 103; tmp.tm_mon= 8; tmp.tm_mday= 1;
2597
tmp.tm_hour= 25; tmp.tm_min=0; tmp.tm_sec=0; tmp.tm_isdst=1;
2599
printf("mktime %s unnormalized input (%d)\n",
2600
(t != (time_t)-1 ? "handles" : "doesn't handle"), (int)t);
2602
tmp.tm_year= 103; tmp.tm_mon= 9; tmp.tm_mday= 26;
2603
tmp.tm_hour= 0; tmp.tm_min= 30; tmp.tm_sec= 0; tmp.tm_isdst= 1;
2605
tmp.tm_hour= 2; tmp.tm_isdst= -1;
2607
tmp.tm_hour= 4; tmp.tm_isdst= 0;
2609
tmp.tm_hour= 2; tmp.tm_isdst= -1;
2611
printf("mktime is %s (%d %d)\n",
2612
(t == t1 ? "determenistic" : "is non-determenistic"),
2615
/* Let us load time zone description */
2616
str_end= strmake(fullname, TZDIR, FN_REFLEN);
2617
strmake(str_end, "/MET", FN_REFLEN - (str_end - fullname));
2619
if (tz_load(fullname, &tz_info, &tz_storage))
2621
printf("Unable to load time zone info from '%s'\n", fullname);
2622
free_root(&tz_storage, MYF(0));
2626
printf("Testing our implementation\n");
2628
if (TYPE_SIGNED(time_t) && localtime_negative)
2630
for (t= -40000; t < 20000; t++)
2632
localtime_r(&t, &tmp);
2633
gmt_sec_to_TIME(&time_tmp, (my_time_t)t, &tz_info);
2634
if (!is_equal_TIME_tm(&time_tmp, &tmp))
2636
printf("Problem with negative time_t = %d\n", (int)t);
2637
free_root(&tz_storage, MYF(0));
2641
printf("gmt_sec_to_TIME = localtime for time_t in [-40000,20000) range\n");
2644
for (t= 1000000000; t < 1100000000; t+= 13)
2646
localtime_r(&t,&tmp);
2647
gmt_sec_to_TIME(&time_tmp, (my_time_t)t, &tz_info);
2649
if (!is_equal_TIME_tm(&time_tmp, &tmp))
2651
printf("Problem with time_t = %d\n", (int)t);
2652
free_root(&tz_storage, MYF(0));
2656
printf("gmt_sec_to_TIME = localtime for time_t in [1000000000,1100000000) range\n");
2661
Be careful here! my_system_gmt_sec doesn't fully handle unnormalized
2664
for (time_tmp.year= 1980; time_tmp.year < 2010; time_tmp.year++)
2666
for (time_tmp.month= 1; time_tmp.month < 13; time_tmp.month++)
2668
for (time_tmp.day= 1;
2669
time_tmp.day < mon_lengths[isleap(time_tmp.year)][time_tmp.month-1];
2672
for (time_tmp.hour= 0; time_tmp.hour < 24; time_tmp.hour++)
2674
for (time_tmp.minute= 0; time_tmp.minute < 60; time_tmp.minute+= 5)
2676
for (time_tmp.second=0; time_tmp.second<60; time_tmp.second+=25)
2680
t= (time_t)my_system_gmt_sec(&time_tmp, ¬_used, ¬_used_2);
2681
t1= (time_t)TIME_to_gmt_sec(&time_tmp, &tz_info, ¬_used_2);
2685
We need special handling during autumn since my_system_gmt_sec
2686
prefers greater time_t values (in MET) for ambiguity.
2687
And BTW that is a bug which should be fixed !!!
2689
tmp.tm_year= time_tmp.year - TM_YEAR_BASE;
2690
tmp.tm_mon= time_tmp.month - 1;
2691
tmp.tm_mday= time_tmp.day;
2692
tmp.tm_hour= time_tmp.hour;
2693
tmp.tm_min= time_tmp.minute;
2694
tmp.tm_sec= time_tmp.second;
2702
printf("Problem: %u/%u/%u %u:%u:%u with times t=%d, t1=%d\n",
2703
time_tmp.year, time_tmp.month, time_tmp.day,
2704
time_tmp.hour, time_tmp.minute, time_tmp.second,
2707
free_root(&tz_storage, MYF(0));
2717
printf("TIME_to_gmt_sec = my_system_gmt_sec for test range\n");
2719
free_root(&tz_storage, MYF(0));
2723
#endif /* defined(TESTTIME) */