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]=
1555
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)
1558
TABLE_LIST tz_tables[1+MY_TZ_TABLES_COUNT];
1559
Open_tables_state open_tables_state_backup;
1561
Tz_names_entry *tmp_tzname;
1562
my_bool return_val= 1;
1567
To be able to run this from boot, we allocate a temporary THD
1569
if (!(thd= new THD))
1571
thd->thread_stack= (char*) &thd;
1572
thd->store_globals();
1575
/* Init all memory structures that require explicit destruction */
1576
if (hash_init(&tz_names, &my_charset_latin1, 20,
1577
0, 0, (hash_get_key) my_tz_names_get_key, 0, 0))
1579
sql_print_error("Fatal error: OOM while initializing time zones");
1582
if (hash_init(&offset_tzs, &my_charset_latin1, 26, 0, 0,
1583
(hash_get_key)my_offset_tzs_get_key, 0, 0))
1585
sql_print_error("Fatal error: OOM while initializing time zones");
1586
hash_free(&tz_names);
1589
init_sql_alloc(&tz_storage, 32 * 1024, 0);
1590
VOID(pthread_mutex_init(&tz_LOCK, MY_MUTEX_INIT_FAST));
1593
/* Add 'SYSTEM' time zone to tz_names hash */
1594
if (!(tmp_tzname= new (&tz_storage) Tz_names_entry()))
1596
sql_print_error("Fatal error: OOM while initializing time zones");
1597
goto end_with_cleanup;
1599
tmp_tzname->name.set(STRING_WITH_LEN("SYSTEM"), &my_charset_latin1);
1600
tmp_tzname->tz= my_tz_SYSTEM;
1601
if (my_hash_insert(&tz_names, (const uchar *)tmp_tzname))
1603
sql_print_error("Fatal error: OOM while initializing time zones");
1604
goto end_with_cleanup;
1609
/* If we are in bootstrap mode we should not load time zone tables */
1610
return_val= time_zone_tables_exist= 0;
1611
goto end_with_setting_default_tz;
1615
After this point all memory structures are inited and we even can live
1616
without time zone description tables. Now try to load information about
1617
leap seconds shared by all time zones.
1620
thd->set_db(db, sizeof(db)-1);
1621
bzero((char*) &tz_tables[0], sizeof(TABLE_LIST));
1622
tz_tables[0].alias= tz_tables[0].table_name=
1623
(char*)"time_zone_leap_second";
1624
tz_tables[0].table_name_length= 21;
1625
tz_tables[0].db= db;
1626
tz_tables[0].db_length= sizeof(db)-1;
1627
tz_tables[0].lock_type= TL_READ;
1629
tz_init_table_list(tz_tables+1);
1630
tz_tables[0].next_global= tz_tables[0].next_local= &tz_tables[1];
1631
tz_tables[1].prev_global= &tz_tables[0].next_global;
1634
We need to open only mysql.time_zone_leap_second, but we try to
1635
open all time zone tables to see if they exist.
1637
if (open_system_tables_for_read(thd, tz_tables, &open_tables_state_backup))
1639
sql_print_warning("Can't open and lock time zone table: %s "
1640
"trying to live without them", thd->main_da.message());
1641
/* We will try emulate that everything is ok */
1642
return_val= time_zone_tables_exist= 0;
1643
goto end_with_setting_default_tz;
1647
Now we are going to load leap seconds descriptions that are shared
1648
between all time zones that use them. We are using index for getting
1649
records in proper order. Since we share the same MEM_ROOT between
1650
all time zones we just allocate enough memory for it first.
1652
if (!(tz_lsis= (LS_INFO*) alloc_root(&tz_storage,
1653
sizeof(LS_INFO) * TZ_MAX_LEAPS)))
1655
sql_print_error("Fatal error: Out of memory while loading "
1656
"mysql.time_zone_leap_second table");
1657
goto end_with_close;
1660
table= tz_tables[0].table;
1662
It is OK to ignore ha_index_init()/ha_index_end() return values since
1663
mysql.time_zone* tables are MyISAM and these operations always succeed
1666
(void)table->file->ha_index_init(0, 1);
1667
table->use_all_columns();
1671
res= table->file->index_first(table->record[0]);
1675
if (tz_leapcnt + 1 > TZ_MAX_LEAPS)
1677
sql_print_error("Fatal error: While loading mysql.time_zone_leap_second"
1678
" table: too much leaps");
1679
table->file->ha_index_end();
1680
goto end_with_close;
1683
tz_lsis[tz_leapcnt].ls_trans= (my_time_t)table->field[0]->val_int();
1684
tz_lsis[tz_leapcnt].ls_corr= (long)table->field[1]->val_int();
1689
res= table->file->index_next(table->record[0]);
1692
(void)table->file->ha_index_end();
1694
if (res != HA_ERR_END_OF_FILE)
1696
sql_print_error("Fatal error: Error while loading "
1697
"mysql.time_zone_leap_second table");
1698
goto end_with_close;
1702
Loading of info about leap seconds succeeded
1708
end_with_setting_default_tz:
1709
/* If we have default time zone try to load it */
1710
1056
if (default_tzname)
1712
1058
String tmp_tzname2(default_tzname, &my_charset_latin1);
1720
1066
sql_print_error("Fatal error: Illegal or unknown default time zone '%s'",
1721
1067
default_tzname);
1727
if (time_zone_tables_exist)
1729
thd->version--; /* Force close to free memory */
1730
close_system_tables(thd, &open_tables_state_backup);
1735
/* if there were error free time zone describing structs */
1741
org_thd->store_globals(); /* purecov: inspected */
1744
/* Remember that we don't have a THD */
1745
my_pthread_setspecific_ptr(THR_THD, 0);
1746
my_pthread_setspecific_ptr(THR_MALLOC, 0);
1753
1077
Free resources used by time zone support infrastructure.
1759
1080
void my_tz_free()
1764
VOID(pthread_mutex_destroy(&tz_LOCK));
1765
hash_free(&offset_tzs);
1766
hash_free(&tz_names);
1767
free_root(&tz_storage, MYF(0));
1773
Load time zone description from system tables.
1776
tz_load_from_open_tables()
1777
tz_name - name of time zone that should be loaded.
1778
tz_tables - list of tables from which time zone description
1782
This function will try to load information about time zone specified
1783
from the list of the already opened and locked tables (first table in
1784
tz_tables should be time_zone_name, next time_zone, then
1785
time_zone_transition_type and time_zone_transition should be last).
1786
It will also update information in hash used for time zones lookup.
1789
Returns pointer to newly created Time_zone object or 0 in case of error.
1794
tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
1797
TIME_ZONE_INFO *tz_info;
1798
Tz_names_entry *tmp_tzname;
1799
Time_zone *return_val= 0;
1803
char buff[MAX_FIELD_WIDTH];
1804
String abbr(buff, sizeof(buff), &my_charset_latin1);
1805
char *alloc_buff, *tz_name_buff;
1807
Temporary arrays that are used for loading of data for filling
1808
TIME_ZONE_INFO structure
1810
my_time_t ats[TZ_MAX_TIMES];
1811
uchar types[TZ_MAX_TIMES];
1812
TRAN_TYPE_INFO ttis[TZ_MAX_TYPES];
1813
#ifdef ABBR_ARE_USED
1814
char chars[max(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1)))];
1817
/* Prepare tz_info for loading also let us make copy of time zone name */
1818
if (!(alloc_buff= (char*) alloc_root(&tz_storage, sizeof(TIME_ZONE_INFO) +
1819
tz_name->length() + 1)))
1821
sql_print_error("Out of memory while loading time zone description");
1824
tz_info= (TIME_ZONE_INFO *)alloc_buff;
1825
bzero(tz_info, sizeof(TIME_ZONE_INFO));
1826
tz_name_buff= alloc_buff + sizeof(TIME_ZONE_INFO);
1828
By writing zero to the end we guarantee that we can call ptr()
1829
instead of c_ptr() for time zone name.
1831
strmake(tz_name_buff, tz_name->ptr(), tz_name->length());
1834
Let us find out time zone id by its name (there is only one index
1835
and it is specifically for this purpose).
1837
table= tz_tables->table;
1838
tz_tables= tz_tables->next_local;
1839
table->field[0]->store(tz_name->ptr(), tz_name->length(),
1840
&my_charset_latin1);
1842
It is OK to ignore ha_index_init()/ha_index_end() return values since
1843
mysql.time_zone* tables are MyISAM and these operations always succeed
1846
(void)table->file->ha_index_init(0, 1);
1848
if (table->file->index_read_map(table->record[0], table->field[0]->ptr,
1849
HA_WHOLE_KEY, HA_READ_KEY_EXACT))
1853
Most probably user has mistyped time zone name, so no need to bark here
1854
unless we need it for debugging.
1856
sql_print_error("Can't find description of time zone '%s'", tz_name_buff);
1861
tzid= (uint)table->field[1]->val_int();
1863
(void)table->file->ha_index_end();
1866
Now we need to lookup record in mysql.time_zone table in order to
1867
understand whenever this timezone uses leap seconds (again we are
1868
using the only index in this table).
1870
table= tz_tables->table;
1871
tz_tables= tz_tables->next_local;
1872
table->field[0]->store((longlong) tzid, TRUE);
1873
(void)table->file->ha_index_init(0, 1);
1875
if (table->file->index_read_map(table->record[0], table->field[0]->ptr,
1876
HA_WHOLE_KEY, HA_READ_KEY_EXACT))
1878
sql_print_error("Can't find description of time zone '%u'", tzid);
1882
/* If Uses_leap_seconds == 'Y' */
1883
if (table->field[1]->val_int() == 1)
1885
tz_info->leapcnt= tz_leapcnt;
1886
tz_info->lsis= tz_lsis;
1889
(void)table->file->ha_index_end();
1892
Now we will iterate through records for out time zone in
1893
mysql.time_zone_transition_type table. Because we want records
1894
only for our time zone guess what are we doing?
1895
Right - using special index.
1897
table= tz_tables->table;
1898
tz_tables= tz_tables->next_local;
1899
table->field[0]->store((longlong) tzid, TRUE);
1900
(void)table->file->ha_index_init(0, 1);
1902
res= table->file->index_read_map(table->record[0], table->field[0]->ptr,
1903
(key_part_map)1, HA_READ_KEY_EXACT);
1906
ttid= (uint)table->field[1]->val_int();
1908
if (ttid >= TZ_MAX_TYPES)
1910
sql_print_error("Error while loading time zone description from "
1911
"mysql.time_zone_transition_type table: too big "
1912
"transition type id");
1916
ttis[ttid].tt_gmtoff= (long)table->field[2]->val_int();
1917
ttis[ttid].tt_isdst= (table->field[3]->val_int() > 0);
1919
#ifdef ABBR_ARE_USED
1920
// FIXME should we do something with duplicates here ?
1921
table->field[4]->val_str(&abbr, &abbr);
1922
if (tz_info->charcnt + abbr.length() + 1 > sizeof(chars))
1924
sql_print_error("Error while loading time zone description from "
1925
"mysql.time_zone_transition_type table: not enough "
1926
"room for abbreviations");
1929
ttis[ttid].tt_abbrind= tz_info->charcnt;
1930
memcpy(chars + tz_info->charcnt, abbr.ptr(), abbr.length());
1931
tz_info->charcnt+= abbr.length();
1932
chars[tz_info->charcnt]= 0;
1937
/* ttid is increasing because we are reading using index */
1938
DBUG_ASSERT(ttid >= tz_info->typecnt);
1940
tz_info->typecnt= ttid + 1;
1942
res= table->file->index_next_same(table->record[0],
1943
table->field[0]->ptr, 4);
1946
if (res != HA_ERR_END_OF_FILE)
1948
sql_print_error("Error while loading time zone description from "
1949
"mysql.time_zone_transition_type table");
1953
(void)table->file->ha_index_end();
1957
At last we are doing the same thing for records in
1958
mysql.time_zone_transition table. Here we additionaly need records
1959
in ascending order by index scan also satisfies us.
1961
table= tz_tables->table;
1962
table->field[0]->store((longlong) tzid, TRUE);
1963
(void)table->file->ha_index_init(0, 1);
1965
res= table->file->index_read_map(table->record[0], table->field[0]->ptr,
1966
(key_part_map)1, HA_READ_KEY_EXACT);
1969
ttime= (my_time_t)table->field[1]->val_int();
1970
ttid= (uint)table->field[2]->val_int();
1972
if (tz_info->timecnt + 1 > TZ_MAX_TIMES)
1974
sql_print_error("Error while loading time zone description from "
1975
"mysql.time_zone_transition table: "
1976
"too much transitions");
1979
if (ttid + 1 > tz_info->typecnt)
1981
sql_print_error("Error while loading time zone description from "
1982
"mysql.time_zone_transition table: "
1983
"bad transition type id");
1987
ats[tz_info->timecnt]= ttime;
1988
types[tz_info->timecnt]= ttid;
1992
res= table->file->index_next_same(table->record[0],
1993
table->field[0]->ptr, 4);
1997
We have to allow HA_ERR_KEY_NOT_FOUND because some time zones
1998
for example UTC have no transitons.
2000
if (res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
2002
sql_print_error("Error while loading time zone description from "
2003
"mysql.time_zone_transition table");
2007
(void)table->file->ha_index_end();
2011
Now we will allocate memory and init TIME_ZONE_INFO structure.
2013
if (!(alloc_buff= (char*) alloc_root(&tz_storage,
2014
ALIGN_SIZE(sizeof(my_time_t) *
2016
ALIGN_SIZE(tz_info->timecnt) +
2017
#ifdef ABBR_ARE_USED
2018
ALIGN_SIZE(tz_info->charcnt) +
2020
sizeof(TRAN_TYPE_INFO) *
2023
sql_print_error("Out of memory while loading time zone description");
2027
tz_info->ats= (my_time_t *) alloc_buff;
2028
memcpy(tz_info->ats, ats, tz_info->timecnt * sizeof(my_time_t));
2029
alloc_buff+= ALIGN_SIZE(sizeof(my_time_t) * tz_info->timecnt);
2030
tz_info->types= (uchar *)alloc_buff;
2031
memcpy(tz_info->types, types, tz_info->timecnt);
2032
alloc_buff+= ALIGN_SIZE(tz_info->timecnt);
2033
#ifdef ABBR_ARE_USED
2034
tz_info->chars= alloc_buff;
2035
memcpy(tz_info->chars, chars, tz_info->charcnt);
2036
alloc_buff+= ALIGN_SIZE(tz_info->charcnt);
2038
tz_info->ttis= (TRAN_TYPE_INFO *)alloc_buff;
2039
memcpy(tz_info->ttis, ttis, tz_info->typecnt * sizeof(TRAN_TYPE_INFO));
2042
Let us check how correct our time zone description and build
2043
reversed map. We don't check for tz->timecnt < 1 since it ok for GMT.
2045
if (tz_info->typecnt < 1)
2047
sql_print_error("loading time zone without transition types");
2050
if (prepare_tz_info(tz_info, &tz_storage))
2052
sql_print_error("Unable to build mktime map for time zone");
2057
if (!(tmp_tzname= new (&tz_storage) Tz_names_entry()) ||
2058
!(tmp_tzname->tz= new (&tz_storage) Time_zone_db(tz_info,
2059
&(tmp_tzname->name))) ||
2060
(tmp_tzname->name.set(tz_name_buff, tz_name->length(),
2061
&my_charset_latin1),
2062
my_hash_insert(&tz_names, (const uchar *)tmp_tzname)))
2064
sql_print_error("Out of memory while loading time zone");
2069
Loading of time zone succeeded
2071
return_val= tmp_tzname->tz;
2076
(void)table->file->ha_index_end();
2163
1166
Get Time_zone object for specified time zone.
2167
thd - pointer to thread THD structure
2168
name - time zone specification
2171
This function checks if name is one of time zones described in db,
2172
predefined SYSTEM time zone or valid time zone specification as
2173
offset from UTC (In last case it will create proper Time_zone_offset
2174
object if there were not any.). If name is ok it returns corresponding
2177
Clients of this function are not responsible for releasing resources
2178
occupied by returned Time_zone object so they can just forget pointers
2179
to Time_zone object if they are not needed longer.
2181
Other important property of this function: if some Time_zone found once
2182
it will be for sure found later, so this function can also be used for
2183
checking if proper Time_zone object exists (and if there will be error
2184
it will be reported during first call).
2186
If name pointer is 0 then this function returns 0 (this allows to pass 0
2187
values as parameter without additional external check and this property
2188
is used by @@time_zone variable handling code).
2190
It will perform lookup in system tables (mysql.time_zone*),
2191
opening and locking them, and closing afterwards. It won't perform
2192
such lookup if no time zone describing tables were found during
2196
Pointer to corresponding Time_zone object. 0 - in case of bad time zone
2197
specification or other error.
1168
Not implemented yet. This needs to hook into some sort of OS system call.
2201
1172
my_tz_find(THD *thd, const String *name)
2203
Tz_names_entry *tmp_tzname;
2204
Time_zone *result_tz= 0;
2210
VOID(pthread_mutex_lock(&tz_LOCK));
2212
if (!str_to_offset(name->ptr(), name->length(), &offset))
2215
if (!(result_tz= (Time_zone_offset *)hash_search(&offset_tzs,
2216
(const uchar *)&offset,
2220
if (!(result_tz= new (&tz_storage) Time_zone_offset(offset)) ||
2221
my_hash_insert(&offset_tzs, (const uchar *) result_tz))
2224
sql_print_error("Fatal error: Out of memory "
2225
"while setting new time zone");
2232
if ((tmp_tzname= (Tz_names_entry *)hash_search(&tz_names,
2233
(const uchar *)name->ptr(),
2235
result_tz= tmp_tzname->tz;
2236
else if (time_zone_tables_exist)
2238
TABLE_LIST tz_tables[MY_TZ_TABLES_COUNT];
2239
Open_tables_state open_tables_state_backup;
2241
tz_init_table_list(tz_tables);
2242
if (!open_system_tables_for_read(thd, tz_tables,
2243
&open_tables_state_backup))
2245
result_tz= tz_load_from_open_tables(name, tz_tables);
2246
close_system_tables(thd, &open_tables_state_backup);
2251
VOID(pthread_mutex_unlock(&tz_LOCK));
2257
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
2262
This code belongs to mysql_tzinfo_to_sql converter command line utility.
2263
This utility should be used by db admin for populating mysql.time_zone
2269
Print info about time zone described by TIME_ZONE_INFO struct as
2270
SQL statements populating mysql.time_zone* tables.
2274
tz_name - name of time zone
2275
sp - structure describing time zone
2278
print_tz_as_sql(const char* tz_name, const TIME_ZONE_INFO *sp)
2282
/* Here we assume that all time zones have same leap correction tables */
2283
printf("INSERT INTO time_zone (Use_leap_seconds) VALUES ('%s');\n",
2284
sp->leapcnt ? "Y" : "N");
2285
printf("SET @time_zone_id= LAST_INSERT_ID();\n");
2286
printf("INSERT INTO time_zone_name (Name, Time_zone_id) VALUES \
2287
('%s', @time_zone_id);\n", tz_name);
2291
printf("INSERT INTO time_zone_transition \
2292
(Time_zone_id, Transition_time, Transition_type_id) VALUES\n");
2293
for (i= 0; i < sp->timecnt; i++)
2294
printf("%s(@time_zone_id, %ld, %u)\n", (i == 0 ? " " : ","), sp->ats[i],
2295
(uint)sp->types[i]);
2299
printf("INSERT INTO time_zone_transition_type \
2300
(Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES\n");
2302
for (i= 0; i < sp->typecnt; i++)
2303
printf("%s(@time_zone_id, %u, %ld, %d, '%s')\n", (i == 0 ? " " : ","), i,
2304
sp->ttis[i].tt_gmtoff, sp->ttis[i].tt_isdst,
2305
sp->chars + sp->ttis[i].tt_abbrind);
2311
Print info about leap seconds in time zone as SQL statements
2312
populating mysql.time_zone_leap_second table.
2315
print_tz_leaps_as_sql()
2316
sp - structure describing time zone
2319
print_tz_leaps_as_sql(const TIME_ZONE_INFO *sp)
2324
We are assuming that there are only one list of leap seconds
2327
printf("TRUNCATE TABLE time_zone_leap_second;\n");
2331
printf("INSERT INTO time_zone_leap_second \
2332
(Transition_time, Correction) VALUES\n");
2333
for (i= 0; i < sp->leapcnt; i++)
2334
printf("%s(%ld, %ld)\n", (i == 0 ? " " : ","),
2335
sp->lsis[i].ls_trans, sp->lsis[i].ls_corr);
2339
printf("ALTER TABLE time_zone_leap_second ORDER BY Transition_time;\n");
2344
Some variables used as temporary or as parameters
2345
in recursive scan_tz_dir() code.
2347
TIME_ZONE_INFO tz_info;
2348
MEM_ROOT tz_storage;
2349
char fullname[FN_REFLEN + 1];
2350
char *root_name_end;
2354
Recursively scan zoneinfo directory and print all found time zone
2355
descriptions as SQL.
2359
name_end - pointer to end of path to directory to be searched.
2362
This auxiliary recursive function also uses several global
2363
variables as in parameters and for storing temporary values.
2365
fullname - path to directory that should be scanned.
2366
root_name_end - pointer to place in fullname where part with
2367
path to initial directory ends.
2368
current_tz_id - last used time zone id
2371
0 - Ok, 1 - Fatal error
2375
scan_tz_dir(char * name_end)
2381
if (!(cur_dir= my_dir(fullname, MYF(MY_WANT_STAT))))
2384
name_end= strmake(name_end, "/", FN_REFLEN - (name_end - fullname));
2386
for (i= 0; i < cur_dir->number_off_files; i++)
2388
if (cur_dir->dir_entry[i].name[0] != '.')
2390
name_end_tmp= strmake(name_end, cur_dir->dir_entry[i].name,
2391
FN_REFLEN - (name_end - fullname));
2393
if (MY_S_ISDIR(cur_dir->dir_entry[i].mystat->st_mode))
2395
if (scan_tz_dir(name_end_tmp))
2401
else if (MY_S_ISREG(cur_dir->dir_entry[i].mystat->st_mode))
2403
init_alloc_root(&tz_storage, 32768, 0);
2404
if (!tz_load(fullname, &tz_info, &tz_storage))
2405
print_tz_as_sql(root_name_end + 1, &tz_info);
2408
"Warning: Unable to load '%s' as time zone. Skipping it.\n",
2410
free_root(&tz_storage, MYF(0));
2413
fprintf(stderr, "Warning: '%s' is not regular file or directory\n",
2425
main(int argc, char **argv)
2429
if (argc != 2 && argc != 3)
2431
fprintf(stderr, "Usage:\n");
2432
fprintf(stderr, " %s timezonedir\n", argv[0]);
2433
fprintf(stderr, " %s timezonefile timezonename\n", argv[0]);
2434
fprintf(stderr, " %s --leap timezonefile\n", argv[0]);
2440
root_name_end= strmake(fullname, argv[1], FN_REFLEN);
2442
printf("TRUNCATE TABLE time_zone;\n");
2443
printf("TRUNCATE TABLE time_zone_name;\n");
2444
printf("TRUNCATE TABLE time_zone_transition;\n");
2445
printf("TRUNCATE TABLE time_zone_transition_type;\n");
2447
if (scan_tz_dir(root_name_end))
2449
fprintf(stderr, "There were fatal errors during processing "
2450
"of zoneinfo directory\n");
2454
printf("ALTER TABLE time_zone_transition "
2455
"ORDER BY Time_zone_id, Transition_time;\n");
2456
printf("ALTER TABLE time_zone_transition_type "
2457
"ORDER BY Time_zone_id, Transition_type_id;\n");
2461
init_alloc_root(&tz_storage, 32768, 0);
2463
if (strcmp(argv[1], "--leap") == 0)
2465
if (tz_load(argv[2], &tz_info, &tz_storage))
2467
fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[2]);
2470
print_tz_leaps_as_sql(&tz_info);
2474
if (tz_load(argv[1], &tz_info, &tz_storage))
2476
fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[2]);
2479
print_tz_as_sql(argv[2], &tz_info);
2482
free_root(&tz_storage, MYF(0));
2488
#endif /* defined(TZINFO2SQL) */
2494
Some simple brute-force test wich allowed to catch a pair of bugs.
2495
Also can provide interesting facts about system's time zone support
2504
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
2508
#define TYPE_SIGNED(type) (((type) -1) < 0)
2512
is_equal_TIME_tm(const TIME* time_arg, const struct tm * tm_arg)
2514
return (time_arg->year == (uint)tm_arg->tm_year+TM_YEAR_BASE) &&
2515
(time_arg->month == (uint)tm_arg->tm_mon+1) &&
2516
(time_arg->day == (uint)tm_arg->tm_mday) &&
2517
(time_arg->hour == (uint)tm_arg->tm_hour) &&
2518
(time_arg->minute == (uint)tm_arg->tm_min) &&
2519
(time_arg->second == (uint)tm_arg->tm_sec) &&
2520
time_arg->second_part == 0;
2525
main(int argc, char **argv)
2527
my_bool localtime_negative;
2528
TIME_ZONE_INFO tz_info;
2530
MYSQL_TIME time_tmp;
2532
char fullname[FN_REFLEN+1];
2534
MEM_ROOT tz_storage;
2538
init_alloc_root(&tz_storage, 32768, 0);
2540
/* let us set some well known timezone */
2541
setenv("TZ", "MET", 1);
2544
/* Some initial time zone related system info */
2545
printf("time_t: %s %u bit\n", TYPE_SIGNED(time_t) ? "signed" : "unsigned",
2546
(uint)TYPE_BIT(time_t));
2547
if (TYPE_SIGNED(time_t))
2550
localtime_negative= test(localtime_r(&t, &tmp) != 0);
2551
printf("localtime_r %s negative params \
2552
(time_t=%d is %d-%d-%d %d:%d:%d)\n",
2553
(localtime_negative ? "supports" : "doesn't support"), (int)t,
2554
TM_YEAR_BASE + tmp.tm_year, tmp.tm_mon + 1, tmp.tm_mday,
2555
tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
2557
printf("mktime %s negative results (%d)\n",
2558
(t == mktime(&tmp) ? "doesn't support" : "supports"),
2562
tmp.tm_year= 103; tmp.tm_mon= 2; tmp.tm_mday= 30;
2563
tmp.tm_hour= 2; tmp.tm_min= 30; tmp.tm_sec= 0; tmp.tm_isdst= -1;
2565
printf("mktime returns %s for spring time gap (%d)\n",
2566
(t != (time_t)-1 ? "something" : "error"), (int)t);
2568
tmp.tm_year= 103; tmp.tm_mon= 8; tmp.tm_mday= 1;
2569
tmp.tm_hour= 0; tmp.tm_min= 0; tmp.tm_sec= 0; tmp.tm_isdst= 0;
2571
printf("mktime returns %s for non existing date (%d)\n",
2572
(t != (time_t)-1 ? "something" : "error"), (int)t);
2574
tmp.tm_year= 103; tmp.tm_mon= 8; tmp.tm_mday= 1;
2575
tmp.tm_hour= 25; tmp.tm_min=0; tmp.tm_sec=0; tmp.tm_isdst=1;
2577
printf("mktime %s unnormalized input (%d)\n",
2578
(t != (time_t)-1 ? "handles" : "doesn't handle"), (int)t);
2580
tmp.tm_year= 103; tmp.tm_mon= 9; tmp.tm_mday= 26;
2581
tmp.tm_hour= 0; tmp.tm_min= 30; tmp.tm_sec= 0; tmp.tm_isdst= 1;
2583
tmp.tm_hour= 2; tmp.tm_isdst= -1;
2585
tmp.tm_hour= 4; tmp.tm_isdst= 0;
2587
tmp.tm_hour= 2; tmp.tm_isdst= -1;
2589
printf("mktime is %s (%d %d)\n",
2590
(t == t1 ? "determenistic" : "is non-determenistic"),
2593
/* Let us load time zone description */
2594
str_end= strmake(fullname, TZDIR, FN_REFLEN);
2595
strmake(str_end, "/MET", FN_REFLEN - (str_end - fullname));
2597
if (tz_load(fullname, &tz_info, &tz_storage))
2599
printf("Unable to load time zone info from '%s'\n", fullname);
2600
free_root(&tz_storage, MYF(0));
2604
printf("Testing our implementation\n");
2606
if (TYPE_SIGNED(time_t) && localtime_negative)
2608
for (t= -40000; t < 20000; t++)
2610
localtime_r(&t, &tmp);
2611
gmt_sec_to_TIME(&time_tmp, (my_time_t)t, &tz_info);
2612
if (!is_equal_TIME_tm(&time_tmp, &tmp))
2614
printf("Problem with negative time_t = %d\n", (int)t);
2615
free_root(&tz_storage, MYF(0));
2619
printf("gmt_sec_to_TIME = localtime for time_t in [-40000,20000) range\n");
2622
for (t= 1000000000; t < 1100000000; t+= 13)
2624
localtime_r(&t,&tmp);
2625
gmt_sec_to_TIME(&time_tmp, (my_time_t)t, &tz_info);
2627
if (!is_equal_TIME_tm(&time_tmp, &tmp))
2629
printf("Problem with time_t = %d\n", (int)t);
2630
free_root(&tz_storage, MYF(0));
2634
printf("gmt_sec_to_TIME = localtime for time_t in [1000000000,1100000000) range\n");
2639
Be careful here! my_system_gmt_sec doesn't fully handle unnormalized
2642
for (time_tmp.year= 1980; time_tmp.year < 2010; time_tmp.year++)
2644
for (time_tmp.month= 1; time_tmp.month < 13; time_tmp.month++)
2646
for (time_tmp.day= 1;
2647
time_tmp.day < mon_lengths[isleap(time_tmp.year)][time_tmp.month-1];
2650
for (time_tmp.hour= 0; time_tmp.hour < 24; time_tmp.hour++)
2652
for (time_tmp.minute= 0; time_tmp.minute < 60; time_tmp.minute+= 5)
2654
for (time_tmp.second=0; time_tmp.second<60; time_tmp.second+=25)
2658
t= (time_t)my_system_gmt_sec(&time_tmp, ¬_used, ¬_used_2);
2659
t1= (time_t)TIME_to_gmt_sec(&time_tmp, &tz_info, ¬_used_2);
2663
We need special handling during autumn since my_system_gmt_sec
2664
prefers greater time_t values (in MET) for ambiguity.
2665
And BTW that is a bug which should be fixed !!!
2667
tmp.tm_year= time_tmp.year - TM_YEAR_BASE;
2668
tmp.tm_mon= time_tmp.month - 1;
2669
tmp.tm_mday= time_tmp.day;
2670
tmp.tm_hour= time_tmp.hour;
2671
tmp.tm_min= time_tmp.minute;
2672
tmp.tm_sec= time_tmp.second;
2680
printf("Problem: %u/%u/%u %u:%u:%u with times t=%d, t1=%d\n",
2681
time_tmp.year, time_tmp.month, time_tmp.day,
2682
time_tmp.hour, time_tmp.minute, time_tmp.second,
2685
free_root(&tz_storage, MYF(0));
2695
printf("TIME_to_gmt_sec = my_system_gmt_sec for test range\n");
2697
free_root(&tz_storage, MYF(0));
2701
#endif /* defined(TESTTIME) */