~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to sql/tztime.cc

  • Committer: Monty Taylor
  • Date: 2008-07-05 11:38:34 UTC
  • mfrom: (60 drizzle)
  • mto: This revision was merged to the branch mainline in revision 62.
  • Revision ID: monty@inaugust.com-20080705113834-23bn0884hk8pqfu9
MergedĀ fromĀ trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
   along with this program; if not, write to the Free Software
14
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
 
/*
17
 
   Most of the following code and structures were derived from
18
 
   public domain code from ftp://elsie.nci.nih.gov/pub
19
 
   (We will refer to this code as to elsie-code further.)
20
 
*/
21
 
 
22
 
/*
23
 
  We should not include mysql_priv.h in mysql_tzinfo_to_sql utility since
24
 
  it creates unsolved link dependencies on some platforms.
25
 
*/
26
 
 
27
16
#ifdef USE_PRAGMA_IMPLEMENTATION
28
17
#pragma implementation                          // gcc: Class implementation
29
18
#endif
30
19
 
31
20
#include <my_global.h>
32
 
#if !defined(TZINFO2SQL) && !defined(TESTTIME)
33
21
#include "mysql_priv.h"
34
 
#else
35
22
#include <my_time.h>
36
 
#include "tztime.h"
37
 
#include <my_sys.h>
38
 
#endif
39
23
 
40
24
#include "tzfile.h"
41
25
#include <m_string.h>
42
 
#include <my_dir.h>
43
 
 
44
 
/*
45
 
  Now we don't use abbreviations in server but we will do this in future.
46
 
*/
47
 
#if defined(TZINFO2SQL) || defined(TESTTIME)
48
 
#define ABBR_ARE_USED
49
 
#else
50
 
#if !defined(DBUG_OFF)
51
 
/* Let use abbreviations for debug purposes */
52
 
#undef ABBR_ARE_USED
53
 
#define ABBR_ARE_USED
54
 
#endif /* !defined(DBUG_OFF) */
55
 
#endif /* defined(TZINFO2SQL) || defined(TESTTIME) */
56
26
 
57
27
/* Structure describing local time type (e.g. Moscow summer time (MSD)) */
58
28
typedef struct ttinfo
59
29
{
60
30
  long tt_gmtoff; // Offset from UTC in seconds
61
31
  uint tt_isdst;   // Is daylight saving time or not. Used to set tm_isdst
62
 
#ifdef ABBR_ARE_USED
63
32
  uint tt_abbrind; // Index of start of abbreviation for this time type.
64
 
#endif
65
33
  /*
66
34
    We don't use tt_ttisstd and tt_ttisgmt members of original elsie-code
67
35
    struct since we don't support POSIX-style TZ descriptions in variables.
108
76
  my_time_t *ats;       // Times of transitions between time types
109
77
  uchar *types; // Local time types for transitions
110
78
  TRAN_TYPE_INFO *ttis; // Local time types descriptions
111
 
#ifdef ABBR_ARE_USED
112
79
  /* Storage for local time types abbreviations. They are stored as ASCIIZ */
113
80
  char *chars;
114
 
#endif
115
81
  /*
116
82
    Leap seconds corrections descriptions, this array is shared by
117
83
    all time zones who use leap seconds.
133
99
} TIME_ZONE_INFO;
134
100
 
135
101
 
136
 
static my_bool prepare_tz_info(TIME_ZONE_INFO *sp, MEM_ROOT *storage);
137
 
 
138
 
 
139
 
#if defined(TZINFO2SQL) || defined(TESTTIME)
140
 
 
141
 
/*
142
 
  Load time zone description from zoneinfo (TZinfo) file.
143
 
 
144
 
  SYNOPSIS
145
 
    tz_load()
146
 
      name - path to zoneinfo file
147
 
      sp   - TIME_ZONE_INFO structure to fill
148
 
 
149
 
  RETURN VALUES
150
 
    0 - Ok
151
 
    1 - Error
152
 
*/
153
 
static my_bool
154
 
tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
155
 
{
156
 
  uchar *p;
157
 
  int read_from_file;
158
 
  uint i;
159
 
  FILE *file;
160
 
 
161
 
  if (!(file= my_fopen(name, O_RDONLY|O_BINARY, MYF(MY_WME))))
162
 
    return 1;
163
 
  {
164
 
    union
165
 
    {
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 +
169
 
#ifdef ABBR_ARE_USED
170
 
               max(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1))) +
171
 
#endif
172
 
               sizeof(LS_INFO) * TZ_MAX_LEAPS];
173
 
    } u;
174
 
    uint ttisstdcnt;
175
 
    uint ttisgmtcnt;
176
 
    char *tzinfo_buf;
177
 
 
178
 
    read_from_file= my_fread(file, u.buf, sizeof(u.buf), MYF(MY_WME));
179
 
 
180
 
    if (my_fclose(file, MYF(MY_WME)) != 0)
181
 
      return 1;
182
 
 
183
 
    if (read_from_file < (int)sizeof(struct tzhead))
184
 
      return 1;
185
 
 
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))
199
 
      return 1;
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 */
208
 
      return 1;
209
 
 
210
 
    if (!(tzinfo_buf= (char *)alloc_root(storage,
211
 
                                         ALIGN_SIZE(sp->timecnt *
212
 
                                                    sizeof(my_time_t)) +
213
 
                                         ALIGN_SIZE(sp->timecnt) +
214
 
                                         ALIGN_SIZE(sp->typecnt *
215
 
                                                    sizeof(TRAN_TYPE_INFO)) +
216
 
#ifdef ABBR_ARE_USED
217
 
                                         ALIGN_SIZE(sp->charcnt) +
218
 
#endif
219
 
                                         sp->leapcnt * sizeof(LS_INFO))))
220
 
      return 1;
221
 
 
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));
228
 
#ifdef ABBR_ARE_USED
229
 
    sp->chars= tzinfo_buf;
230
 
    tzinfo_buf+= ALIGN_SIZE(sp->charcnt);
231
 
#endif
232
 
    sp->lsis= (LS_INFO *)tzinfo_buf;
233
 
 
234
 
    for (i= 0; i < sp->timecnt; i++, p+= 4)
235
 
      sp->ats[i]= int4net(p);
236
 
 
237
 
    for (i= 0; i < sp->timecnt; i++)
238
 
    {
239
 
      sp->types[i]= (uchar) *p++;
240
 
      if (sp->types[i] >= sp->typecnt)
241
 
        return 1;
242
 
    }
243
 
    for (i= 0; i < sp->typecnt; i++)
244
 
    {
245
 
      TRAN_TYPE_INFO * ttisp;
246
 
 
247
 
      ttisp= &sp->ttis[i];
248
 
      ttisp->tt_gmtoff= int4net(p);
249
 
      p+= 4;
250
 
      ttisp->tt_isdst= (uchar) *p++;
251
 
      if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
252
 
        return 1;
253
 
      ttisp->tt_abbrind= (uchar) *p++;
254
 
      if (ttisp->tt_abbrind > sp->charcnt)
255
 
        return 1;
256
 
    }
257
 
    for (i= 0; i < sp->charcnt; i++)
258
 
      sp->chars[i]= *p++;
259
 
    sp->chars[i]= '\0'; /* ensure '\0' at end */
260
 
    for (i= 0; i < sp->leapcnt; i++)
261
 
    {
262
 
      LS_INFO *lsisp;
263
 
 
264
 
      lsisp= &sp->lsis[i];
265
 
      lsisp->ls_trans= int4net(p);
266
 
      p+= 4;
267
 
      lsisp->ls_corr= int4net(p);
268
 
      p+= 4;
269
 
    }
270
 
    /*
271
 
      Since we don't support POSIX style TZ definitions in variables we
272
 
      don't read further like glibc or elsie code.
273
 
    */
274
 
  }
275
 
 
276
 
  return prepare_tz_info(sp, storage);
277
 
}
278
 
#endif /* defined(TZINFO2SQL) || defined(TESTTIME) */
279
 
 
280
 
 
281
 
/*
282
 
  Finish preparation of time zone description for use in TIME_to_gmt_sec()
283
 
  and gmt_sec_to_TIME() functions.
284
 
 
285
 
  SYNOPSIS
286
 
    prepare_tz_info()
287
 
      sp - pointer to time zone description
288
 
      storage - pointer to MEM_ROOT where arrays for map allocated
289
 
 
290
 
  DESCRIPTION
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
293
 
    any transitions.
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).
308
 
 
309
 
  RETURN VALUES
310
 
    0   Ok
311
 
    1   Error
312
 
*/
313
 
static my_bool
314
 
prepare_tz_info(TIME_ZONE_INFO *sp, MEM_ROOT *storage)
315
 
{
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;
321
 
  uint i;
322
 
  /*
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.)
326
 
  */
327
 
  my_time_t revts[TZ_MAX_REV_RANGES];
328
 
  REVT_INFO revtis[TZ_MAX_REV_RANGES];
329
 
 
330
 
  /*
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).
335
 
  */
336
 
  for (i= 0; i < sp->typecnt && sp->ttis[i].tt_isdst; i++)
337
 
    /* no-op */ ;
338
 
  if (i == sp->typecnt)
339
 
    i= 0;
340
 
  sp->fallback_tti= &(sp->ttis[i]);
341
 
 
342
 
 
343
 
  /*
344
 
    Let us build shifted my_time_t -> my_time_t map.
345
 
  */
346
 
  sp->revcnt= 0;
347
 
 
348
 
  /* Let us find initial offset */
349
 
  if (sp->timecnt == 0 || cur_t < sp->ats[0])
350
 
  {
351
 
    /*
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.
354
 
    */
355
 
    next_trans_idx= 0;
356
 
  }
357
 
  else
358
 
  {
359
 
    /* cur_t == sp->ats[0] so we found transition */
360
 
    i= sp->types[0];
361
 
    next_trans_idx= 1;
362
 
  }
363
 
 
364
 
  cur_offset= sp->ttis[i].tt_gmtoff;
365
 
 
366
 
 
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;
370
 
         ++next_leap_idx)
371
 
    continue;
372
 
 
373
 
  if (next_leap_idx > 0)
374
 
    cur_corr= sp->lsis[next_leap_idx - 1].ls_corr;
375
 
  else
376
 
    cur_corr= 0;
377
 
 
378
 
  /* Iterate trough t space */
379
 
  while (sp->revcnt < TZ_MAX_REV_RANGES - 1)
380
 
  {
381
 
    cur_off_and_corr= cur_offset - cur_corr;
382
 
 
383
 
    /*
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.
386
 
    */
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;
390
 
 
391
 
    cur_l= cur_t + cur_off_and_corr;
392
 
 
393
 
    /*
394
 
      Let us choose end_t as point before next time type change or leap
395
 
      second correction.
396
 
    */
397
 
    end_t= min((next_trans_idx < sp->timecnt) ? sp->ats[next_trans_idx] - 1:
398
 
                                                MY_TIME_T_MAX,
399
 
               (next_leap_idx < sp->leapcnt) ?
400
 
                 sp->lsis[next_leap_idx].ls_trans - 1: MY_TIME_T_MAX);
401
 
    /*
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.
404
 
    */
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;
408
 
 
409
 
    end_l= end_t + cur_off_and_corr;
410
 
 
411
 
 
412
 
    if (end_l > cur_max_seen_l)
413
 
    {
414
 
      /* We want special handling in the case of first range */
415
 
      if (cur_max_seen_l == MY_TIME_T_MIN)
416
 
      {
417
 
        revts[sp->revcnt]= cur_l;
418
 
        revtis[sp->revcnt].rt_offset= cur_off_and_corr;
419
 
        revtis[sp->revcnt].rt_type= 0;
420
 
        sp->revcnt++;
421
 
        cur_max_seen_l= end_l;
422
 
      }
423
 
      else
424
 
      {
425
 
        if (cur_l > cur_max_seen_l + 1)
426
 
        {
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;
431
 
          sp->revcnt++;
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;
435
 
        }
436
 
 
437
 
        /* Assume here end_l > cur_max_seen_l (because end_l>=cur_l) */
438
 
 
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;
442
 
        sp->revcnt++;
443
 
        cur_max_seen_l= end_l;
444
 
      }
445
 
    }
446
 
 
447
 
    if (end_t == MY_TIME_T_MAX ||
448
 
        ((cur_off_and_corr > 0) && (end_t >= MY_TIME_T_MAX - cur_off_and_corr)))
449
 
      /* end of t space */
450
 
      break;
451
 
 
452
 
    cur_t= end_t + 1;
453
 
 
454
 
    /*
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.
458
 
    */
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])
462
 
      {
463
 
        /* We are at offset point */
464
 
        cur_offset= sp->ttis[sp->types[next_trans_idx]].tt_gmtoff;
465
 
        ++next_trans_idx;
466
 
      }
467
 
 
468
 
    if (next_leap_idx < sp->leapcnt &&
469
 
        cur_t == sp->lsis[next_leap_idx].ls_trans)
470
 
    {
471
 
      /* we are at leap point */
472
 
      cur_corr= sp->lsis[next_leap_idx].ls_corr;
473
 
      ++next_leap_idx;
474
 
    }
475
 
  }
476
 
 
477
 
  /* check if we have had enough space */
478
 
  if (sp->revcnt == TZ_MAX_REV_RANGES - 1)
479
 
    return 1;
480
 
 
481
 
  /* set maximum end_l as finisher */
482
 
  revts[sp->revcnt]= end_l;
483
 
 
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)))
489
 
    return 1;
490
 
 
491
 
  memcpy(sp->revts, revts, sizeof(my_time_t) * (sp->revcnt + 1));
492
 
  memcpy(sp->revtis, revtis, sizeof(REVT_INFO) * sp->revcnt);
493
 
 
494
 
  return 0;
495
 
}
496
 
 
497
 
 
498
102
#if !defined(TZINFO2SQL)
499
103
 
500
104
static const uint mon_lengths[2][MONS_PER_YEAR]=
982
586
#endif /* !defined(TZINFO2SQL) */
983
587
 
984
588
 
985
 
#if !defined(TESTTIME) && !defined(TZINFO2SQL)
986
 
 
987
589
/*
988
590
  String with names of SYSTEM time zone.
989
591
*/
1415
1017
Time_zone *my_tz_UTC= &tz_UTC;
1416
1018
Time_zone *my_tz_SYSTEM= &tz_SYSTEM;
1417
1019
 
1418
 
static HASH tz_names;
1419
 
static HASH offset_tzs;
1420
 
static MEM_ROOT tz_storage;
1421
 
 
1422
 
/*
1423
 
  These mutex protects offset_tzs and tz_storage.
1424
 
  These protection needed only when we are trying to set
1425
 
  time zone which is specified as offset, and searching for existing
1426
 
  time zone in offset_tzs or creating if it didn't existed before in
1427
 
  tz_storage. So contention is low.
1428
 
*/
1429
 
static pthread_mutex_t tz_LOCK;
1430
 
static bool tz_inited= 0;
1431
 
 
1432
 
/*
1433
 
  This two static variables are inteded for holding info about leap seconds
1434
 
  shared by all time zones.
1435
 
*/
1436
 
static uint tz_leapcnt= 0;
1437
 
static LS_INFO *tz_lsis= 0;
1438
 
 
1439
 
/*
1440
 
  Shows whenever we have found time zone tables during start-up.
1441
 
  Used for avoiding of putting those tables to global table list
1442
 
  for queries that use time zone info.
1443
 
*/
1444
 
static bool time_zone_tables_exist= 1;
1445
 
 
1446
 
 
1447
 
/*
1448
 
  Names of tables (with their lengths) that are needed
1449
 
  for dynamical loading of time zone descriptions.
1450
 
*/
1451
 
 
1452
 
static const LEX_STRING tz_tables_names[MY_TZ_TABLES_COUNT]=
1453
 
{
1454
 
  { C_STRING_WITH_LEN("time_zone_name")},
1455
 
  { C_STRING_WITH_LEN("time_zone")},
1456
 
  { C_STRING_WITH_LEN("time_zone_transition_type")},
1457
 
  { C_STRING_WITH_LEN("time_zone_transition")}
1458
 
};
1459
 
 
1460
 
/* Name of database to which those tables belong. */
1461
 
 
1462
 
static const LEX_STRING tz_tables_db_name= { C_STRING_WITH_LEN("mysql")};
1463
 
 
1464
 
 
1465
1020
class Tz_names_entry: public Sql_alloc
1466
1021
{
1467
1022
public:
1471
1026
 
1472
1027
 
1473
1028
/*
1474
 
  We are going to call both of these functions from C code so
1475
 
  they should obey C calling conventions.
1476
 
*/
1477
 
 
1478
 
extern "C" uchar *
1479
 
my_tz_names_get_key(Tz_names_entry *entry, size_t *length,
1480
 
                    my_bool not_used __attribute__((unused)))
1481
 
{
1482
 
  *length= entry->name.length();
1483
 
  return (uchar*) entry->name.ptr();
1484
 
}
1485
 
 
1486
 
extern "C" uchar *
1487
 
my_offset_tzs_get_key(Time_zone_offset *entry,
1488
 
                      size_t *length,
1489
 
                      my_bool not_used __attribute__((unused)))
1490
 
{
1491
 
  *length= sizeof(long);
1492
 
  return (uchar*) &entry->offset;
1493
 
}
1494
 
 
1495
 
 
1496
 
/*
1497
 
  Prepare table list with time zone related tables from preallocated array.
1498
 
 
1499
 
  SYNOPSIS
1500
 
    tz_init_table_list()
1501
 
      tz_tabs         - pointer to preallocated array of MY_TZ_TABLES_COUNT
1502
 
                        TABLE_LIST objects
1503
 
 
1504
 
  DESCRIPTION
1505
 
    This function prepares list of TABLE_LIST objects which can be used
1506
 
    for opening of time zone tables from preallocated array.
1507
 
*/
1508
 
 
1509
 
static void
1510
 
tz_init_table_list(TABLE_LIST *tz_tabs)
1511
 
{
1512
 
  bzero(tz_tabs, sizeof(TABLE_LIST) * MY_TZ_TABLES_COUNT);
1513
 
 
1514
 
  for (int i= 0; i < MY_TZ_TABLES_COUNT; i++)
1515
 
  {
1516
 
    tz_tabs[i].alias= tz_tabs[i].table_name= tz_tables_names[i].str;
1517
 
    tz_tabs[i].table_name_length= tz_tables_names[i].length;
1518
 
    tz_tabs[i].db= tz_tables_db_name.str;
1519
 
    tz_tabs[i].db_length= tz_tables_db_name.length;
1520
 
    tz_tabs[i].lock_type= TL_READ;
1521
 
 
1522
 
    if (i != MY_TZ_TABLES_COUNT - 1)
1523
 
      tz_tabs[i].next_global= tz_tabs[i].next_local= &tz_tabs[i+1];
1524
 
    if (i != 0)
1525
 
      tz_tabs[i].prev_global= &tz_tabs[i-1].next_global;
1526
 
  }
1527
 
}
1528
 
 
1529
 
 
1530
 
/*
1531
1029
  Initialize time zone support infrastructure.
1532
1030
 
1533
1031
  SYNOPSIS
1552
1050
    0 - ok
1553
1051
    1 - Error
1554
1052
*/
1555
 
my_bool
1556
 
my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
 
1053
bool
 
1054
my_tz_init(THD *thd, const char *default_tzname, my_bool bootstrap)
1557
1055
{
1558
 
  THD *thd;
1559
 
  TABLE_LIST tz_tables[1+MY_TZ_TABLES_COUNT];
1560
 
  Open_tables_state open_tables_state_backup;
1561
 
  TABLE *table;
1562
 
  Tz_names_entry *tmp_tzname;
1563
 
  my_bool return_val= 1;
1564
 
  char db[]= "mysql";
1565
 
  int res;
1566
 
  DBUG_ENTER("my_tz_init");
1567
 
 
1568
 
  /*
1569
 
    To be able to run this from boot, we allocate a temporary THD
1570
 
  */
1571
 
  if (!(thd= new THD))
1572
 
    DBUG_RETURN(1);
1573
 
  thd->thread_stack= (char*) &thd;
1574
 
  thd->store_globals();
1575
 
  lex_start(thd);
1576
 
 
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))
1580
 
  {
1581
 
    sql_print_error("Fatal error: OOM while initializing time zones");
1582
 
    goto end;
1583
 
  }
1584
 
  if (hash_init(&offset_tzs, &my_charset_latin1, 26, 0, 0,
1585
 
                (hash_get_key)my_offset_tzs_get_key, 0, 0))
1586
 
  {
1587
 
    sql_print_error("Fatal error: OOM while initializing time zones");
1588
 
    hash_free(&tz_names);
1589
 
    goto end;
1590
 
  }
1591
 
  init_sql_alloc(&tz_storage, 32 * 1024, 0);
1592
 
  VOID(pthread_mutex_init(&tz_LOCK, MY_MUTEX_INIT_FAST));
1593
 
  tz_inited= 1;
1594
 
 
1595
 
  /* Add 'SYSTEM' time zone to tz_names hash */
1596
 
  if (!(tmp_tzname= new (&tz_storage) Tz_names_entry()))
1597
 
  {
1598
 
    sql_print_error("Fatal error: OOM while initializing time zones");
1599
 
    goto end_with_cleanup;
1600
 
  }
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))
1604
 
  {
1605
 
    sql_print_error("Fatal error: OOM while initializing time zones");
1606
 
    goto end_with_cleanup;
1607
 
  }
1608
 
 
1609
 
  if (bootstrap)
1610
 
  {
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;
1614
 
  }
1615
 
 
1616
 
  /*
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.
1620
 
  */
1621
 
 
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;
1630
 
 
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;
1634
 
 
1635
 
  /*
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.
1638
 
  */
1639
 
  if (open_system_tables_for_read(thd, tz_tables, &open_tables_state_backup))
1640
 
  {
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;
1646
 
  }
1647
 
 
1648
 
  /*
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.
1653
 
  */
1654
 
  if (!(tz_lsis= (LS_INFO*) alloc_root(&tz_storage,
1655
 
                                       sizeof(LS_INFO) * TZ_MAX_LEAPS)))
1656
 
  {
1657
 
    sql_print_error("Fatal error: Out of memory while loading "
1658
 
                    "mysql.time_zone_leap_second table");
1659
 
    goto end_with_close;
1660
 
  }
1661
 
 
1662
 
  table= tz_tables[0].table;
1663
 
  /*
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
1666
 
    for MyISAM.
1667
 
  */
1668
 
  (void)table->file->ha_index_init(0, 1);
1669
 
  table->use_all_columns();
1670
 
 
1671
 
  tz_leapcnt= 0;
1672
 
 
1673
 
  res= table->file->index_first(table->record[0]);
1674
 
 
1675
 
  while (!res)
1676
 
  {
1677
 
    if (tz_leapcnt + 1 > TZ_MAX_LEAPS)
1678
 
    {
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;
1683
 
    }
1684
 
 
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();
1687
 
 
1688
 
    tz_leapcnt++;
1689
 
 
1690
 
    DBUG_PRINT("info",
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));
1694
 
 
1695
 
    res= table->file->index_next(table->record[0]);
1696
 
  }
1697
 
 
1698
 
  (void)table->file->ha_index_end();
1699
 
 
1700
 
  if (res != HA_ERR_END_OF_FILE)
1701
 
  {
1702
 
    sql_print_error("Fatal error: Error while loading "
1703
 
                    "mysql.time_zone_leap_second table");
1704
 
    goto end_with_close;
1705
 
  }
1706
 
 
1707
 
  /*
1708
 
    Loading of info about leap seconds succeeded
1709
 
  */
1710
 
 
1711
 
  return_val= 0;
1712
 
 
1713
 
 
1714
 
end_with_setting_default_tz:
1715
 
  /* If we have default time zone try to load it */
1716
1056
  if (default_tzname)
1717
1057
  {
1718
1058
    String tmp_tzname2(default_tzname, &my_charset_latin1);
1725
1065
    {
1726
1066
      sql_print_error("Fatal error: Illegal or unknown default time zone '%s'",
1727
1067
                      default_tzname);
1728
 
      return_val= 1;
 
1068
      return true;
1729
1069
    }
1730
1070
  }
1731
1071
 
1732
 
end_with_close:
1733
 
  if (time_zone_tables_exist)
1734
 
  {
1735
 
    thd->version--; /* Force close to free memory */
1736
 
    close_system_tables(thd, &open_tables_state_backup);
1737
 
  }
1738
 
 
1739
 
end_with_cleanup:
1740
 
 
1741
 
  /* if there were error free time zone describing structs */
1742
 
  if (return_val)
1743
 
    my_tz_free();
1744
 
end:
1745
 
  delete thd;
1746
 
  if (org_thd)
1747
 
    org_thd->store_globals();                   /* purecov: inspected */
1748
 
  else
1749
 
  {
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);
1753
 
  }
1754
 
  DBUG_RETURN(return_val);
 
1072
  return false;
1755
1073
}
1756
1074
 
1757
1075
 
1758
1076
/*
1759
1077
  Free resources used by time zone support infrastructure.
1760
 
 
1761
 
  SYNOPSIS
1762
 
    my_tz_free()
1763
1078
*/
1764
1079
 
1765
1080
void my_tz_free()
1766
1081
{
1767
 
  if (tz_inited)
1768
 
  {
1769
 
    tz_inited= 0;
1770
 
    VOID(pthread_mutex_destroy(&tz_LOCK));
1771
 
    hash_free(&offset_tzs);
1772
 
    hash_free(&tz_names);
1773
 
    free_root(&tz_storage, MYF(0));
1774
 
  }
1775
 
}
1776
 
 
1777
 
 
1778
 
/*
1779
 
  Load time zone description from system tables.
1780
 
 
1781
 
  SYNOPSIS
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
1785
 
                  should be loaded
1786
 
 
1787
 
  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.
1793
 
 
1794
 
  RETURN VALUES
1795
 
    Returns pointer to newly created Time_zone object or 0 in case of error.
1796
 
 
1797
 
*/
1798
 
 
1799
 
static Time_zone*
1800
 
tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
1801
 
{
1802
 
  TABLE *table= 0;
1803
 
  TIME_ZONE_INFO *tz_info;
1804
 
  Tz_names_entry *tmp_tzname;
1805
 
  Time_zone *return_val= 0;
1806
 
  int res;
1807
 
  uint tzid, ttid;
1808
 
  my_time_t ttime;
1809
 
  char buff[MAX_FIELD_WIDTH];
1810
 
  String abbr(buff, sizeof(buff), &my_charset_latin1);
1811
 
  char *alloc_buff, *tz_name_buff;
1812
 
  /*
1813
 
    Temporary arrays that are used for loading of data for filling
1814
 
    TIME_ZONE_INFO structure
1815
 
  */
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)))];
1821
 
#endif
1822
 
  DBUG_ENTER("tz_load_from_open_tables");
1823
 
 
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)))
1827
 
  {
1828
 
    sql_print_error("Out of memory while loading time zone description");
1829
 
    return 0;
1830
 
  }
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);
1834
 
  /*
1835
 
    By writing zero to the end we guarantee that we can call ptr()
1836
 
    instead of c_ptr() for time zone name.
1837
 
  */
1838
 
  strmake(tz_name_buff, tz_name->ptr(), tz_name->length());
1839
 
 
1840
 
  /*
1841
 
    Let us find out time zone id by its name (there is only one index
1842
 
    and it is specifically for this purpose).
1843
 
  */
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);
1848
 
  /*
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
1851
 
    for MyISAM.
1852
 
  */
1853
 
  (void)table->file->ha_index_init(0, 1);
1854
 
 
1855
 
  if (table->file->index_read_map(table->record[0], table->field[0]->ptr,
1856
 
                                  HA_WHOLE_KEY, HA_READ_KEY_EXACT))
1857
 
  {
1858
 
#ifdef EXTRA_DEBUG
1859
 
    /*
1860
 
      Most probably user has mistyped time zone name, so no need to bark here
1861
 
      unless we need it for debugging.
1862
 
    */
1863
 
    sql_print_error("Can't find description of time zone '%s'", tz_name_buff);
1864
 
#endif
1865
 
    goto end;
1866
 
  }
1867
 
 
1868
 
  tzid= (uint)table->field[1]->val_int();
1869
 
 
1870
 
  (void)table->file->ha_index_end();
1871
 
 
1872
 
  /*
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).
1876
 
  */
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);
1881
 
 
1882
 
  if (table->file->index_read_map(table->record[0], table->field[0]->ptr,
1883
 
                                  HA_WHOLE_KEY, HA_READ_KEY_EXACT))
1884
 
  {
1885
 
    sql_print_error("Can't find description of time zone '%u'", tzid);
1886
 
    goto end;
1887
 
  }
1888
 
 
1889
 
  /* If Uses_leap_seconds == 'Y' */
1890
 
  if (table->field[1]->val_int() == 1)
1891
 
  {
1892
 
    tz_info->leapcnt= tz_leapcnt;
1893
 
    tz_info->lsis= tz_lsis;
1894
 
  }
1895
 
 
1896
 
  (void)table->file->ha_index_end();
1897
 
 
1898
 
  /*
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.
1903
 
  */
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);
1908
 
 
1909
 
  res= table->file->index_read_map(table->record[0], table->field[0]->ptr,
1910
 
                                   (key_part_map)1, HA_READ_KEY_EXACT);
1911
 
  while (!res)
1912
 
  {
1913
 
    ttid= (uint)table->field[1]->val_int();
1914
 
 
1915
 
    if (ttid >= TZ_MAX_TYPES)
1916
 
    {
1917
 
      sql_print_error("Error while loading time zone description from "
1918
 
                      "mysql.time_zone_transition_type table: too big "
1919
 
                      "transition type id");
1920
 
      goto end;
1921
 
    }
1922
 
 
1923
 
    ttis[ttid].tt_gmtoff= (long)table->field[2]->val_int();
1924
 
    ttis[ttid].tt_isdst= (table->field[3]->val_int() > 0);
1925
 
 
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))
1930
 
    {
1931
 
      sql_print_error("Error while loading time zone description from "
1932
 
                      "mysql.time_zone_transition_type table: not enough "
1933
 
                      "room for abbreviations");
1934
 
      goto end;
1935
 
    }
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;
1940
 
    tz_info->charcnt++;
1941
 
 
1942
 
    DBUG_PRINT("info",
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));
1946
 
#else
1947
 
    DBUG_PRINT("info",
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));
1950
 
#endif
1951
 
 
1952
 
    /* ttid is increasing because we are reading using index */
1953
 
    DBUG_ASSERT(ttid >= tz_info->typecnt);
1954
 
 
1955
 
    tz_info->typecnt= ttid + 1;
1956
 
 
1957
 
    res= table->file->index_next_same(table->record[0],
1958
 
                                      table->field[0]->ptr, 4);
1959
 
  }
1960
 
 
1961
 
  if (res != HA_ERR_END_OF_FILE)
1962
 
  {
1963
 
    sql_print_error("Error while loading time zone description from "
1964
 
                    "mysql.time_zone_transition_type table");
1965
 
    goto end;
1966
 
  }
1967
 
 
1968
 
  (void)table->file->ha_index_end();
1969
 
 
1970
 
 
1971
 
  /*
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.
1975
 
  */
1976
 
  table= tz_tables->table; 
1977
 
  table->field[0]->store((longlong) tzid, TRUE);
1978
 
  (void)table->file->ha_index_init(0, 1);
1979
 
 
1980
 
  res= table->file->index_read_map(table->record[0], table->field[0]->ptr,
1981
 
                                   (key_part_map)1, HA_READ_KEY_EXACT);
1982
 
  while (!res)
1983
 
  {
1984
 
    ttime= (my_time_t)table->field[1]->val_int();
1985
 
    ttid= (uint)table->field[2]->val_int();
1986
 
 
1987
 
    if (tz_info->timecnt + 1 > TZ_MAX_TIMES)
1988
 
    {
1989
 
      sql_print_error("Error while loading time zone description from "
1990
 
                      "mysql.time_zone_transition table: "
1991
 
                      "too much transitions");
1992
 
      goto end;
1993
 
    }
1994
 
    if (ttid + 1 > tz_info->typecnt)
1995
 
    {
1996
 
      sql_print_error("Error while loading time zone description from "
1997
 
                      "mysql.time_zone_transition table: "
1998
 
                      "bad transition type id");
1999
 
      goto end;
2000
 
    }
2001
 
 
2002
 
    ats[tz_info->timecnt]= ttime;
2003
 
    types[tz_info->timecnt]= ttid;
2004
 
    tz_info->timecnt++;
2005
 
 
2006
 
    DBUG_PRINT("info",
2007
 
      ("time_zone_transition table: tz_id: %u  tt_time: %lu  tt_id: %u",
2008
 
       tzid, (ulong) ttime, ttid));
2009
 
 
2010
 
    res= table->file->index_next_same(table->record[0],
2011
 
                                      table->field[0]->ptr, 4);
2012
 
  }
2013
 
 
2014
 
  /*
2015
 
    We have to allow HA_ERR_KEY_NOT_FOUND because some time zones
2016
 
    for example UTC have no transitons.
2017
 
  */
2018
 
  if (res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
2019
 
  {
2020
 
    sql_print_error("Error while loading time zone description from "
2021
 
                    "mysql.time_zone_transition table");
2022
 
    goto end;
2023
 
  }
2024
 
 
2025
 
  (void)table->file->ha_index_end();
2026
 
  table= 0;
2027
 
 
2028
 
  /*
2029
 
    Now we will allocate memory and init TIME_ZONE_INFO structure.
2030
 
  */
2031
 
  if (!(alloc_buff= (char*) alloc_root(&tz_storage,
2032
 
                                       ALIGN_SIZE(sizeof(my_time_t) *
2033
 
                                                  tz_info->timecnt) +
2034
 
                                       ALIGN_SIZE(tz_info->timecnt) +
2035
 
#ifdef ABBR_ARE_USED
2036
 
                                       ALIGN_SIZE(tz_info->charcnt) +
2037
 
#endif
2038
 
                                       sizeof(TRAN_TYPE_INFO) *
2039
 
                                       tz_info->typecnt)))
2040
 
  {
2041
 
    sql_print_error("Out of memory while loading time zone description");
2042
 
    goto end;
2043
 
  }
2044
 
 
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);
2055
 
#endif
2056
 
  tz_info->ttis= (TRAN_TYPE_INFO *)alloc_buff;
2057
 
  memcpy(tz_info->ttis, ttis, tz_info->typecnt * sizeof(TRAN_TYPE_INFO));
2058
 
 
2059
 
  /*
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.
2062
 
  */
2063
 
  if (tz_info->typecnt < 1)
2064
 
  {
2065
 
    sql_print_error("loading time zone without transition types");
2066
 
    goto end;
2067
 
  }
2068
 
  if (prepare_tz_info(tz_info, &tz_storage))
2069
 
  {
2070
 
    sql_print_error("Unable to build mktime map for time zone");
2071
 
    goto end;
2072
 
  }
2073
 
 
2074
 
 
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)))
2081
 
  {
2082
 
    sql_print_error("Out of memory while loading time zone");
2083
 
    goto end;
2084
 
  }
2085
 
 
2086
 
  /*
2087
 
    Loading of time zone succeeded
2088
 
  */
2089
 
  return_val= tmp_tzname->tz;
2090
 
 
2091
 
end:
2092
 
 
2093
 
  if (table)
2094
 
    (void)table->file->ha_index_end();
2095
 
 
2096
 
  DBUG_RETURN(return_val);
2097
1082
}
2098
1083
 
2099
1084
 
2180
1165
/*
2181
1166
  Get Time_zone object for specified time zone.
2182
1167
 
2183
 
  SYNOPSIS
2184
 
    my_tz_find()
2185
 
      thd  - pointer to thread THD structure
2186
 
      name - time zone specification
2187
 
 
2188
 
  DESCRIPTION
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
2193
 
    Time_zone object.
2194
 
 
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.
2198
 
 
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).
2203
 
 
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).
2207
 
 
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
2211
 
    server start up.
2212
 
 
2213
 
  RETURN VALUE
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.
2216
1169
 
2217
1170
*/
2218
1171
Time_zone *
2219
1172
my_tz_find(THD *thd, const String *name)
2220
1173
{
2221
 
  Tz_names_entry *tmp_tzname;
2222
 
  Time_zone *result_tz= 0;
2223
 
  long offset;
2224
 
  DBUG_ENTER("my_tz_find");
2225
 
  DBUG_PRINT("enter", ("time zone name='%s'",
2226
 
                       name ? ((String *)name)->c_ptr_safe() : "NULL"));
2227
 
 
2228
 
  if (!name)
2229
 
    DBUG_RETURN(0);
2230
 
 
2231
 
  VOID(pthread_mutex_lock(&tz_LOCK));
2232
 
 
2233
 
  if (!str_to_offset(name->ptr(), name->length(), &offset))
2234
 
  {
2235
 
 
2236
 
    if (!(result_tz= (Time_zone_offset *)hash_search(&offset_tzs,
2237
 
                                                     (const uchar *)&offset,
2238
 
                                                     sizeof(long))))
2239
 
    {
2240
 
      DBUG_PRINT("info", ("Creating new Time_zone_offset object"));
2241
 
 
2242
 
      if (!(result_tz= new (&tz_storage) Time_zone_offset(offset)) ||
2243
 
          my_hash_insert(&offset_tzs, (const uchar *) result_tz))
2244
 
      {
2245
 
        result_tz= 0;
2246
 
        sql_print_error("Fatal error: Out of memory "
2247
 
                        "while setting new time zone");
2248
 
      }
2249
 
    }
2250
 
  }
2251
 
  else
2252
 
  {
2253
 
    result_tz= 0;
2254
 
    if ((tmp_tzname= (Tz_names_entry *)hash_search(&tz_names,
2255
 
                                                   (const uchar *)name->ptr(),
2256
 
                                                   name->length())))
2257
 
      result_tz= tmp_tzname->tz;
2258
 
    else if (time_zone_tables_exist)
2259
 
    {
2260
 
      TABLE_LIST tz_tables[MY_TZ_TABLES_COUNT];
2261
 
      Open_tables_state open_tables_state_backup;
2262
 
 
2263
 
      tz_init_table_list(tz_tables);
2264
 
      if (!open_system_tables_for_read(thd, tz_tables,
2265
 
                                       &open_tables_state_backup))
2266
 
      {
2267
 
        result_tz= tz_load_from_open_tables(name, tz_tables);
2268
 
        close_system_tables(thd, &open_tables_state_backup);
2269
 
      }
2270
 
    }
2271
 
  }
2272
 
 
2273
 
  VOID(pthread_mutex_unlock(&tz_LOCK));
2274
 
 
2275
 
  DBUG_RETURN(result_tz);
2276
 
}
2277
 
 
2278
 
 
2279
 
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
2280
 
 
2281
 
 
2282
 
#ifdef TZINFO2SQL
2283
 
/*
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
2286
 
  tables.
2287
 
*/
2288
 
 
2289
 
 
2290
 
/*
2291
 
  Print info about time zone described by TIME_ZONE_INFO struct as
2292
 
  SQL statements populating mysql.time_zone* tables.
2293
 
 
2294
 
  SYNOPSIS
2295
 
    print_tz_as_sql()
2296
 
      tz_name - name of time zone
2297
 
      sp      - structure describing time zone
2298
 
*/
2299
 
void
2300
 
print_tz_as_sql(const char* tz_name, const TIME_ZONE_INFO *sp)
2301
 
{
2302
 
  uint i;
2303
 
 
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);
2310
 
 
2311
 
  if (sp->timecnt)
2312
 
  {
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]);
2318
 
    printf(";\n");
2319
 
  }
2320
 
 
2321
 
  printf("INSERT INTO time_zone_transition_type \
2322
 
(Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES\n");
2323
 
 
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);
2328
 
  printf(";\n");
2329
 
}
2330
 
 
2331
 
 
2332
 
/*
2333
 
  Print info about leap seconds in time zone as SQL statements
2334
 
  populating mysql.time_zone_leap_second table.
2335
 
 
2336
 
  SYNOPSIS
2337
 
    print_tz_leaps_as_sql()
2338
 
      sp      - structure describing time zone
2339
 
*/
2340
 
void
2341
 
print_tz_leaps_as_sql(const TIME_ZONE_INFO *sp)
2342
 
{
2343
 
  uint i;
2344
 
 
2345
 
  /*
2346
 
    We are assuming that there are only one list of leap seconds
2347
 
    For all timezones.
2348
 
  */
2349
 
  printf("TRUNCATE TABLE time_zone_leap_second;\n");
2350
 
 
2351
 
  if (sp->leapcnt)
2352
 
  {
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);
2358
 
    printf(";\n");
2359
 
  }
2360
 
 
2361
 
  printf("ALTER TABLE time_zone_leap_second ORDER BY Transition_time;\n");
2362
 
}
2363
 
 
2364
 
 
2365
 
/*
2366
 
  Some variables used as temporary or as parameters
2367
 
  in recursive scan_tz_dir() code.
2368
 
*/
2369
 
TIME_ZONE_INFO tz_info;
2370
 
MEM_ROOT tz_storage;
2371
 
char fullname[FN_REFLEN + 1];
2372
 
char *root_name_end;
2373
 
 
2374
 
 
2375
 
/*
2376
 
  Recursively scan zoneinfo directory and print all found time zone
2377
 
  descriptions as SQL.
2378
 
 
2379
 
  SYNOPSIS
2380
 
    scan_tz_dir()
2381
 
      name_end - pointer to end of path to directory to be searched.
2382
 
 
2383
 
  DESCRIPTION
2384
 
    This auxiliary recursive function also uses several global
2385
 
    variables as in parameters and for storing temporary values.
2386
 
 
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
2391
 
 
2392
 
  RETURN VALUE
2393
 
    0 - Ok, 1 - Fatal error
2394
 
 
2395
 
*/
2396
 
my_bool
2397
 
scan_tz_dir(char * name_end)
2398
 
{
2399
 
  MY_DIR *cur_dir;
2400
 
  char *name_end_tmp;
2401
 
  uint i;
2402
 
 
2403
 
  if (!(cur_dir= my_dir(fullname, MYF(MY_WANT_STAT))))
2404
 
    return 1;
2405
 
 
2406
 
  name_end= strmake(name_end, "/", FN_REFLEN - (name_end - fullname));
2407
 
 
2408
 
  for (i= 0; i < cur_dir->number_off_files; i++)
2409
 
  {
2410
 
    if (cur_dir->dir_entry[i].name[0] != '.')
2411
 
    {
2412
 
      name_end_tmp= strmake(name_end, cur_dir->dir_entry[i].name,
2413
 
                            FN_REFLEN - (name_end - fullname));
2414
 
 
2415
 
      if (MY_S_ISDIR(cur_dir->dir_entry[i].mystat->st_mode))
2416
 
      {
2417
 
        if (scan_tz_dir(name_end_tmp))
2418
 
        {
2419
 
          my_dirend(cur_dir);
2420
 
          return 1;
2421
 
        }
2422
 
      }
2423
 
      else if (MY_S_ISREG(cur_dir->dir_entry[i].mystat->st_mode))
2424
 
      {
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);
2428
 
        else
2429
 
          fprintf(stderr,
2430
 
                  "Warning: Unable to load '%s' as time zone. Skipping it.\n",
2431
 
                  fullname);
2432
 
        free_root(&tz_storage, MYF(0));
2433
 
      }
2434
 
      else
2435
 
        fprintf(stderr, "Warning: '%s' is not regular file or directory\n",
2436
 
                fullname);
2437
 
    }
2438
 
  }
2439
 
 
2440
 
  my_dirend(cur_dir);
2441
 
 
2442
 
  return 0;
2443
 
}
2444
 
 
2445
 
 
2446
 
int
2447
 
main(int argc, char **argv)
2448
 
{
2449
 
  MY_INIT(argv[0]);
2450
 
 
2451
 
  if (argc != 2 && argc != 3)
2452
 
  {
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]);
2457
 
    return 1;
2458
 
  }
2459
 
 
2460
 
  if (argc == 2)
2461
 
  {
2462
 
    root_name_end= strmake(fullname, argv[1], FN_REFLEN);
2463
 
 
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");
2468
 
 
2469
 
    if (scan_tz_dir(root_name_end))
2470
 
    {
2471
 
      fprintf(stderr, "There were fatal errors during processing "
2472
 
                      "of zoneinfo directory\n");
2473
 
      return 1;
2474
 
    }
2475
 
 
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");
2480
 
  }
2481
 
  else
2482
 
  {
2483
 
    init_alloc_root(&tz_storage, 32768, 0);
2484
 
 
2485
 
    if (strcmp(argv[1], "--leap") == 0)
2486
 
    {
2487
 
      if (tz_load(argv[2], &tz_info, &tz_storage))
2488
 
      {
2489
 
        fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[2]);
2490
 
        return 1;
2491
 
      }
2492
 
      print_tz_leaps_as_sql(&tz_info);
2493
 
    }
2494
 
    else
2495
 
    {
2496
 
      if (tz_load(argv[1], &tz_info, &tz_storage))
2497
 
      {
2498
 
        fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[2]);
2499
 
        return 1;
2500
 
      }
2501
 
      print_tz_as_sql(argv[2], &tz_info);
2502
 
    }
2503
 
 
2504
 
    free_root(&tz_storage, MYF(0));
2505
 
  }
2506
 
 
2507
 
  return 0;
2508
 
}
2509
 
 
2510
 
#endif /* defined(TZINFO2SQL) */
2511
 
 
2512
 
 
2513
 
#ifdef TESTTIME
2514
 
 
2515
 
/*
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
2518
 
   implementation.
2519
 
*/
2520
 
 
2521
 
#ifndef CHAR_BIT
2522
 
#define CHAR_BIT 8
2523
 
#endif
2524
 
 
2525
 
#ifndef TYPE_BIT
2526
 
#define TYPE_BIT(type)  (sizeof (type) * CHAR_BIT)
2527
 
#endif
2528
 
 
2529
 
#ifndef TYPE_SIGNED
2530
 
#define TYPE_SIGNED(type) (((type) -1) < 0)
2531
 
#endif
2532
 
 
2533
 
my_bool
2534
 
is_equal_TIME_tm(const TIME* time_arg, const struct tm * tm_arg)
2535
 
{
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;
2543
 
}
2544
 
 
2545
 
 
2546
 
int
2547
 
main(int argc, char **argv)
2548
 
{
2549
 
  my_bool localtime_negative;
2550
 
  TIME_ZONE_INFO tz_info;
2551
 
  struct tm tmp;
2552
 
  MYSQL_TIME time_tmp;
2553
 
  time_t t, t1, t2;
2554
 
  char fullname[FN_REFLEN+1];
2555
 
  char *str_end;
2556
 
  MEM_ROOT tz_storage;
2557
 
 
2558
 
  MY_INIT(argv[0]);
2559
 
 
2560
 
  init_alloc_root(&tz_storage, 32768, 0);
2561
 
 
2562
 
  /* let us set some well known timezone */
2563
 
  setenv("TZ", "MET", 1);
2564
 
  tzset();
2565
 
 
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))
2570
 
  {
2571
 
    t= -100;
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);
2578
 
 
2579
 
    printf("mktime %s negative results (%d)\n",
2580
 
           (t == mktime(&tmp) ? "doesn't support" : "supports"),
2581
 
           (int)mktime(&tmp));
2582
 
  }
2583
 
 
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;
2586
 
  t= mktime(&tmp);
2587
 
  printf("mktime returns %s for spring time gap (%d)\n",
2588
 
         (t != (time_t)-1 ? "something" : "error"), (int)t);
2589
 
 
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;
2592
 
  t= mktime(&tmp);
2593
 
  printf("mktime returns %s for non existing date (%d)\n",
2594
 
         (t != (time_t)-1 ? "something" : "error"), (int)t);
2595
 
 
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;
2598
 
  t= mktime(&tmp);
2599
 
  printf("mktime %s unnormalized input (%d)\n",
2600
 
         (t != (time_t)-1 ? "handles" : "doesn't handle"), (int)t);
2601
 
 
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;
2604
 
  mktime(&tmp);
2605
 
  tmp.tm_hour= 2; tmp.tm_isdst= -1;
2606
 
  t= mktime(&tmp);
2607
 
  tmp.tm_hour= 4; tmp.tm_isdst= 0;
2608
 
  mktime(&tmp);
2609
 
  tmp.tm_hour= 2; tmp.tm_isdst= -1;
2610
 
  t1= mktime(&tmp);
2611
 
  printf("mktime is %s (%d %d)\n",
2612
 
         (t == t1 ? "determenistic" : "is non-determenistic"),
2613
 
         (int)t, (int)t1);
2614
 
 
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));
2618
 
 
2619
 
  if (tz_load(fullname, &tz_info, &tz_storage))
2620
 
  {
2621
 
    printf("Unable to load time zone info from '%s'\n", fullname);
2622
 
    free_root(&tz_storage, MYF(0));
2623
 
    return 1;
2624
 
  }
2625
 
 
2626
 
  printf("Testing our implementation\n");
2627
 
 
2628
 
  if (TYPE_SIGNED(time_t) && localtime_negative)
2629
 
  {
2630
 
    for (t= -40000; t < 20000; t++)
2631
 
    {
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))
2635
 
      {
2636
 
        printf("Problem with negative time_t = %d\n", (int)t);
2637
 
        free_root(&tz_storage, MYF(0));
2638
 
        return 1;
2639
 
      }
2640
 
    }
2641
 
    printf("gmt_sec_to_TIME = localtime for time_t in [-40000,20000) range\n");
2642
 
  }
2643
 
 
2644
 
  for (t= 1000000000; t < 1100000000; t+= 13)
2645
 
  {
2646
 
    localtime_r(&t,&tmp);
2647
 
    gmt_sec_to_TIME(&time_tmp, (my_time_t)t, &tz_info);
2648
 
 
2649
 
    if (!is_equal_TIME_tm(&time_tmp, &tmp))
2650
 
    {
2651
 
      printf("Problem with time_t = %d\n", (int)t);
2652
 
      free_root(&tz_storage, MYF(0));
2653
 
      return 1;
2654
 
    }
2655
 
  }
2656
 
  printf("gmt_sec_to_TIME = localtime for time_t in [1000000000,1100000000) range\n");
2657
 
 
2658
 
  init_time();
2659
 
 
2660
 
  /*
2661
 
    Be careful here! my_system_gmt_sec doesn't fully handle unnormalized
2662
 
    dates.
2663
 
  */
2664
 
  for (time_tmp.year= 1980; time_tmp.year < 2010; time_tmp.year++)
2665
 
  {
2666
 
    for (time_tmp.month= 1; time_tmp.month < 13; time_tmp.month++)
2667
 
    {
2668
 
      for (time_tmp.day= 1;
2669
 
           time_tmp.day < mon_lengths[isleap(time_tmp.year)][time_tmp.month-1];
2670
 
           time_tmp.day++)
2671
 
      {
2672
 
        for (time_tmp.hour= 0; time_tmp.hour < 24; time_tmp.hour++)
2673
 
        {
2674
 
          for (time_tmp.minute= 0; time_tmp.minute < 60; time_tmp.minute+= 5)
2675
 
          {
2676
 
            for (time_tmp.second=0; time_tmp.second<60; time_tmp.second+=25)
2677
 
            {
2678
 
              long not_used;
2679
 
              my_bool not_used_2;
2680
 
              t= (time_t)my_system_gmt_sec(&time_tmp, &not_used, &not_used_2);
2681
 
              t1= (time_t)TIME_to_gmt_sec(&time_tmp, &tz_info, &not_used_2);
2682
 
              if (t != t1)
2683
 
              {
2684
 
                /*
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 !!!
2688
 
                */
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;
2695
 
                tmp.tm_isdst= 1;
2696
 
 
2697
 
                t2= mktime(&tmp);
2698
 
 
2699
 
                if (t1 == t2)
2700
 
                  continue;
2701
 
 
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,
2705
 
                       (int)t,(int)t1);
2706
 
 
2707
 
                free_root(&tz_storage, MYF(0));
2708
 
                return 1;
2709
 
              }
2710
 
            }
2711
 
          }
2712
 
        }
2713
 
      }
2714
 
    }
2715
 
  }
2716
 
 
2717
 
  printf("TIME_to_gmt_sec = my_system_gmt_sec for test range\n");
2718
 
 
2719
 
  free_root(&tz_storage, MYF(0));
2720
 
  return 0;
2721
 
}
2722
 
 
2723
 
#endif /* defined(TESTTIME) */
 
1174
  return NULL;
 
1175
}