~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to sql/tztime.cc

Merging trunk changes from over weekend.

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]=
885
489
  uint i;
886
490
  int shift= 0;
887
491
 
 
492
  DBUG_ENTER("TIME_to_gmt_sec");
888
493
 
889
494
  if (!validate_timestamp_range(t))
890
 
    return(0);
 
495
    DBUG_RETURN(0);
891
496
 
892
497
 
893
498
  /* We need this for correct leap seconds handling */
932
537
      This means that source time can't be represented as my_time_t due to
933
538
      limited my_time_t range.
934
539
    */
935
 
    return(0);
 
540
    DBUG_RETURN(0);
936
541
  }
937
542
 
938
543
  /* binary search for our range */
948
553
    if (local_t > (my_time_t) (TIMESTAMP_MAX_VALUE - shift * SECS_PER_DAY +
949
554
                               sp->revtis[i].rt_offset - saved_seconds))
950
555
    {
951
 
      return(0);                           /* my_time_t overflow */
 
556
      DBUG_RETURN(0);                           /* my_time_t overflow */
952
557
    }
953
558
    local_t+= shift * SECS_PER_DAY;
954
559
  }
971
576
  if (local_t < TIMESTAMP_MIN_VALUE)
972
577
    local_t= 0;
973
578
 
974
 
  return(local_t);
 
579
  DBUG_RETURN(local_t);
975
580
}
976
581
 
977
582
 
981
586
#endif /* !defined(TZINFO2SQL) */
982
587
 
983
588
 
984
 
#if !defined(TESTTIME) && !defined(TZINFO2SQL)
985
 
 
986
589
/*
987
590
  String with names of SYSTEM time zone.
988
591
*/
1414
1017
Time_zone *my_tz_UTC= &tz_UTC;
1415
1018
Time_zone *my_tz_SYSTEM= &tz_SYSTEM;
1416
1019
 
1417
 
static HASH tz_names;
1418
 
static HASH offset_tzs;
1419
 
static MEM_ROOT tz_storage;
1420
 
 
1421
 
/*
1422
 
  These mutex protects offset_tzs and tz_storage.
1423
 
  These protection needed only when we are trying to set
1424
 
  time zone which is specified as offset, and searching for existing
1425
 
  time zone in offset_tzs or creating if it didn't existed before in
1426
 
  tz_storage. So contention is low.
1427
 
*/
1428
 
static pthread_mutex_t tz_LOCK;
1429
 
static bool tz_inited= 0;
1430
 
 
1431
 
/*
1432
 
  This two static variables are inteded for holding info about leap seconds
1433
 
  shared by all time zones.
1434
 
*/
1435
 
static uint tz_leapcnt= 0;
1436
 
static LS_INFO *tz_lsis= 0;
1437
 
 
1438
 
/*
1439
 
  Shows whenever we have found time zone tables during start-up.
1440
 
  Used for avoiding of putting those tables to global table list
1441
 
  for queries that use time zone info.
1442
 
*/
1443
 
static bool time_zone_tables_exist= 1;
1444
 
 
1445
 
 
1446
 
/*
1447
 
  Names of tables (with their lengths) that are needed
1448
 
  for dynamical loading of time zone descriptions.
1449
 
*/
1450
 
 
1451
 
static const LEX_STRING tz_tables_names[MY_TZ_TABLES_COUNT]=
1452
 
{
1453
 
  { C_STRING_WITH_LEN("time_zone_name")},
1454
 
  { C_STRING_WITH_LEN("time_zone")},
1455
 
  { C_STRING_WITH_LEN("time_zone_transition_type")},
1456
 
  { C_STRING_WITH_LEN("time_zone_transition")}
1457
 
};
1458
 
 
1459
 
/* Name of database to which those tables belong. */
1460
 
 
1461
 
static const LEX_STRING tz_tables_db_name= { C_STRING_WITH_LEN("mysql")};
1462
 
 
1463
 
 
1464
1020
class Tz_names_entry: public Sql_alloc
1465
1021
{
1466
1022
public:
1470
1026
 
1471
1027
 
1472
1028
/*
1473
 
  We are going to call both of these functions from C code so
1474
 
  they should obey C calling conventions.
1475
 
*/
1476
 
 
1477
 
extern "C" uchar *
1478
 
my_tz_names_get_key(Tz_names_entry *entry, size_t *length,
1479
 
                    my_bool not_used __attribute__((unused)))
1480
 
{
1481
 
  *length= entry->name.length();
1482
 
  return (uchar*) entry->name.ptr();
1483
 
}
1484
 
 
1485
 
extern "C" uchar *
1486
 
my_offset_tzs_get_key(Time_zone_offset *entry,
1487
 
                      size_t *length,
1488
 
                      my_bool not_used __attribute__((unused)))
1489
 
{
1490
 
  *length= sizeof(long);
1491
 
  return (uchar*) &entry->offset;
1492
 
}
1493
 
 
1494
 
 
1495
 
/*
1496
 
  Prepare table list with time zone related tables from preallocated array.
1497
 
 
1498
 
  SYNOPSIS
1499
 
    tz_init_table_list()
1500
 
      tz_tabs         - pointer to preallocated array of MY_TZ_TABLES_COUNT
1501
 
                        TABLE_LIST objects
1502
 
 
1503
 
  DESCRIPTION
1504
 
    This function prepares list of TABLE_LIST objects which can be used
1505
 
    for opening of time zone tables from preallocated array.
1506
 
*/
1507
 
 
1508
 
static void
1509
 
tz_init_table_list(TABLE_LIST *tz_tabs)
1510
 
{
1511
 
  bzero(tz_tabs, sizeof(TABLE_LIST) * MY_TZ_TABLES_COUNT);
1512
 
 
1513
 
  for (int i= 0; i < MY_TZ_TABLES_COUNT; i++)
1514
 
  {
1515
 
    tz_tabs[i].alias= tz_tabs[i].table_name= tz_tables_names[i].str;
1516
 
    tz_tabs[i].table_name_length= tz_tables_names[i].length;
1517
 
    tz_tabs[i].db= tz_tables_db_name.str;
1518
 
    tz_tabs[i].db_length= tz_tables_db_name.length;
1519
 
    tz_tabs[i].lock_type= TL_READ;
1520
 
 
1521
 
    if (i != MY_TZ_TABLES_COUNT - 1)
1522
 
      tz_tabs[i].next_global= tz_tabs[i].next_local= &tz_tabs[i+1];
1523
 
    if (i != 0)
1524
 
      tz_tabs[i].prev_global= &tz_tabs[i-1].next_global;
1525
 
  }
1526
 
}
1527
 
 
1528
 
 
1529
 
/*
1530
1029
  Initialize time zone support infrastructure.
1531
1030
 
1532
1031
  SYNOPSIS
1551
1050
    0 - ok
1552
1051
    1 - Error
1553
1052
*/
1554
 
my_bool
1555
 
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)
1556
1055
{
1557
 
  THD *thd;
1558
 
  TABLE_LIST tz_tables[1+MY_TZ_TABLES_COUNT];
1559
 
  Open_tables_state open_tables_state_backup;
1560
 
  TABLE *table;
1561
 
  Tz_names_entry *tmp_tzname;
1562
 
  my_bool return_val= 1;
1563
 
  char db[]= "mysql";
1564
 
  int res;
1565
 
 
1566
 
  /*
1567
 
    To be able to run this from boot, we allocate a temporary THD
1568
 
  */
1569
 
  if (!(thd= new THD))
1570
 
    return(1);
1571
 
  thd->thread_stack= (char*) &thd;
1572
 
  thd->store_globals();
1573
 
  lex_start(thd);
1574
 
 
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))
1578
 
  {
1579
 
    sql_print_error("Fatal error: OOM while initializing time zones");
1580
 
    goto end;
1581
 
  }
1582
 
  if (hash_init(&offset_tzs, &my_charset_latin1, 26, 0, 0,
1583
 
                (hash_get_key)my_offset_tzs_get_key, 0, 0))
1584
 
  {
1585
 
    sql_print_error("Fatal error: OOM while initializing time zones");
1586
 
    hash_free(&tz_names);
1587
 
    goto end;
1588
 
  }
1589
 
  init_sql_alloc(&tz_storage, 32 * 1024, 0);
1590
 
  VOID(pthread_mutex_init(&tz_LOCK, MY_MUTEX_INIT_FAST));
1591
 
  tz_inited= 1;
1592
 
 
1593
 
  /* Add 'SYSTEM' time zone to tz_names hash */
1594
 
  if (!(tmp_tzname= new (&tz_storage) Tz_names_entry()))
1595
 
  {
1596
 
    sql_print_error("Fatal error: OOM while initializing time zones");
1597
 
    goto end_with_cleanup;
1598
 
  }
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))
1602
 
  {
1603
 
    sql_print_error("Fatal error: OOM while initializing time zones");
1604
 
    goto end_with_cleanup;
1605
 
  }
1606
 
 
1607
 
  if (bootstrap)
1608
 
  {
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;
1612
 
  }
1613
 
 
1614
 
  /*
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.
1618
 
  */
1619
 
 
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;
1628
 
 
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;
1632
 
 
1633
 
  /*
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.
1636
 
  */
1637
 
  if (open_system_tables_for_read(thd, tz_tables, &open_tables_state_backup))
1638
 
  {
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;
1644
 
  }
1645
 
 
1646
 
  /*
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.
1651
 
  */
1652
 
  if (!(tz_lsis= (LS_INFO*) alloc_root(&tz_storage,
1653
 
                                       sizeof(LS_INFO) * TZ_MAX_LEAPS)))
1654
 
  {
1655
 
    sql_print_error("Fatal error: Out of memory while loading "
1656
 
                    "mysql.time_zone_leap_second table");
1657
 
    goto end_with_close;
1658
 
  }
1659
 
 
1660
 
  table= tz_tables[0].table;
1661
 
  /*
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
1664
 
    for MyISAM.
1665
 
  */
1666
 
  (void)table->file->ha_index_init(0, 1);
1667
 
  table->use_all_columns();
1668
 
 
1669
 
  tz_leapcnt= 0;
1670
 
 
1671
 
  res= table->file->index_first(table->record[0]);
1672
 
 
1673
 
  while (!res)
1674
 
  {
1675
 
    if (tz_leapcnt + 1 > TZ_MAX_LEAPS)
1676
 
    {
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;
1681
 
    }
1682
 
 
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();
1685
 
 
1686
 
    tz_leapcnt++;
1687
 
 
1688
 
 
1689
 
    res= table->file->index_next(table->record[0]);
1690
 
  }
1691
 
 
1692
 
  (void)table->file->ha_index_end();
1693
 
 
1694
 
  if (res != HA_ERR_END_OF_FILE)
1695
 
  {
1696
 
    sql_print_error("Fatal error: Error while loading "
1697
 
                    "mysql.time_zone_leap_second table");
1698
 
    goto end_with_close;
1699
 
  }
1700
 
 
1701
 
  /*
1702
 
    Loading of info about leap seconds succeeded
1703
 
  */
1704
 
 
1705
 
  return_val= 0;
1706
 
 
1707
 
 
1708
 
end_with_setting_default_tz:
1709
 
  /* If we have default time zone try to load it */
1710
1056
  if (default_tzname)
1711
1057
  {
1712
1058
    String tmp_tzname2(default_tzname, &my_charset_latin1);
1719
1065
    {
1720
1066
      sql_print_error("Fatal error: Illegal or unknown default time zone '%s'",
1721
1067
                      default_tzname);
1722
 
      return_val= 1;
 
1068
      return true;
1723
1069
    }
1724
1070
  }
1725
1071
 
1726
 
end_with_close:
1727
 
  if (time_zone_tables_exist)
1728
 
  {
1729
 
    thd->version--; /* Force close to free memory */
1730
 
    close_system_tables(thd, &open_tables_state_backup);
1731
 
  }
1732
 
 
1733
 
end_with_cleanup:
1734
 
 
1735
 
  /* if there were error free time zone describing structs */
1736
 
  if (return_val)
1737
 
    my_tz_free();
1738
 
end:
1739
 
  delete thd;
1740
 
  if (org_thd)
1741
 
    org_thd->store_globals();                   /* purecov: inspected */
1742
 
  else
1743
 
  {
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);
1747
 
  }
1748
 
  return(return_val);
 
1072
  return false;
1749
1073
}
1750
1074
 
1751
1075
 
1752
1076
/*
1753
1077
  Free resources used by time zone support infrastructure.
1754
 
 
1755
 
  SYNOPSIS
1756
 
    my_tz_free()
1757
1078
*/
1758
1079
 
1759
1080
void my_tz_free()
1760
1081
{
1761
 
  if (tz_inited)
1762
 
  {
1763
 
    tz_inited= 0;
1764
 
    VOID(pthread_mutex_destroy(&tz_LOCK));
1765
 
    hash_free(&offset_tzs);
1766
 
    hash_free(&tz_names);
1767
 
    free_root(&tz_storage, MYF(0));
1768
 
  }
1769
 
}
1770
 
 
1771
 
 
1772
 
/*
1773
 
  Load time zone description from system tables.
1774
 
 
1775
 
  SYNOPSIS
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
1779
 
                  should be loaded
1780
 
 
1781
 
  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.
1787
 
 
1788
 
  RETURN VALUES
1789
 
    Returns pointer to newly created Time_zone object or 0 in case of error.
1790
 
 
1791
 
*/
1792
 
 
1793
 
static Time_zone*
1794
 
tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
1795
 
{
1796
 
  TABLE *table= 0;
1797
 
  TIME_ZONE_INFO *tz_info;
1798
 
  Tz_names_entry *tmp_tzname;
1799
 
  Time_zone *return_val= 0;
1800
 
  int res;
1801
 
  uint tzid, ttid;
1802
 
  my_time_t ttime;
1803
 
  char buff[MAX_FIELD_WIDTH];
1804
 
  String abbr(buff, sizeof(buff), &my_charset_latin1);
1805
 
  char *alloc_buff, *tz_name_buff;
1806
 
  /*
1807
 
    Temporary arrays that are used for loading of data for filling
1808
 
    TIME_ZONE_INFO structure
1809
 
  */
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)))];
1815
 
#endif
1816
 
 
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)))
1820
 
  {
1821
 
    sql_print_error("Out of memory while loading time zone description");
1822
 
    return 0;
1823
 
  }
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);
1827
 
  /*
1828
 
    By writing zero to the end we guarantee that we can call ptr()
1829
 
    instead of c_ptr() for time zone name.
1830
 
  */
1831
 
  strmake(tz_name_buff, tz_name->ptr(), tz_name->length());
1832
 
 
1833
 
  /*
1834
 
    Let us find out time zone id by its name (there is only one index
1835
 
    and it is specifically for this purpose).
1836
 
  */
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);
1841
 
  /*
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
1844
 
    for MyISAM.
1845
 
  */
1846
 
  (void)table->file->ha_index_init(0, 1);
1847
 
 
1848
 
  if (table->file->index_read_map(table->record[0], table->field[0]->ptr,
1849
 
                                  HA_WHOLE_KEY, HA_READ_KEY_EXACT))
1850
 
  {
1851
 
#ifdef EXTRA_DEBUG
1852
 
    /*
1853
 
      Most probably user has mistyped time zone name, so no need to bark here
1854
 
      unless we need it for debugging.
1855
 
    */
1856
 
    sql_print_error("Can't find description of time zone '%s'", tz_name_buff);
1857
 
#endif
1858
 
    goto end;
1859
 
  }
1860
 
 
1861
 
  tzid= (uint)table->field[1]->val_int();
1862
 
 
1863
 
  (void)table->file->ha_index_end();
1864
 
 
1865
 
  /*
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).
1869
 
  */
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);
1874
 
 
1875
 
  if (table->file->index_read_map(table->record[0], table->field[0]->ptr,
1876
 
                                  HA_WHOLE_KEY, HA_READ_KEY_EXACT))
1877
 
  {
1878
 
    sql_print_error("Can't find description of time zone '%u'", tzid);
1879
 
    goto end;
1880
 
  }
1881
 
 
1882
 
  /* If Uses_leap_seconds == 'Y' */
1883
 
  if (table->field[1]->val_int() == 1)
1884
 
  {
1885
 
    tz_info->leapcnt= tz_leapcnt;
1886
 
    tz_info->lsis= tz_lsis;
1887
 
  }
1888
 
 
1889
 
  (void)table->file->ha_index_end();
1890
 
 
1891
 
  /*
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.
1896
 
  */
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);
1901
 
 
1902
 
  res= table->file->index_read_map(table->record[0], table->field[0]->ptr,
1903
 
                                   (key_part_map)1, HA_READ_KEY_EXACT);
1904
 
  while (!res)
1905
 
  {
1906
 
    ttid= (uint)table->field[1]->val_int();
1907
 
 
1908
 
    if (ttid >= TZ_MAX_TYPES)
1909
 
    {
1910
 
      sql_print_error("Error while loading time zone description from "
1911
 
                      "mysql.time_zone_transition_type table: too big "
1912
 
                      "transition type id");
1913
 
      goto end;
1914
 
    }
1915
 
 
1916
 
    ttis[ttid].tt_gmtoff= (long)table->field[2]->val_int();
1917
 
    ttis[ttid].tt_isdst= (table->field[3]->val_int() > 0);
1918
 
 
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))
1923
 
    {
1924
 
      sql_print_error("Error while loading time zone description from "
1925
 
                      "mysql.time_zone_transition_type table: not enough "
1926
 
                      "room for abbreviations");
1927
 
      goto end;
1928
 
    }
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;
1933
 
    tz_info->charcnt++;
1934
 
 
1935
 
#endif
1936
 
 
1937
 
    /* ttid is increasing because we are reading using index */
1938
 
    DBUG_ASSERT(ttid >= tz_info->typecnt);
1939
 
 
1940
 
    tz_info->typecnt= ttid + 1;
1941
 
 
1942
 
    res= table->file->index_next_same(table->record[0],
1943
 
                                      table->field[0]->ptr, 4);
1944
 
  }
1945
 
 
1946
 
  if (res != HA_ERR_END_OF_FILE)
1947
 
  {
1948
 
    sql_print_error("Error while loading time zone description from "
1949
 
                    "mysql.time_zone_transition_type table");
1950
 
    goto end;
1951
 
  }
1952
 
 
1953
 
  (void)table->file->ha_index_end();
1954
 
 
1955
 
 
1956
 
  /*
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.
1960
 
  */
1961
 
  table= tz_tables->table; 
1962
 
  table->field[0]->store((longlong) tzid, TRUE);
1963
 
  (void)table->file->ha_index_init(0, 1);
1964
 
 
1965
 
  res= table->file->index_read_map(table->record[0], table->field[0]->ptr,
1966
 
                                   (key_part_map)1, HA_READ_KEY_EXACT);
1967
 
  while (!res)
1968
 
  {
1969
 
    ttime= (my_time_t)table->field[1]->val_int();
1970
 
    ttid= (uint)table->field[2]->val_int();
1971
 
 
1972
 
    if (tz_info->timecnt + 1 > TZ_MAX_TIMES)
1973
 
    {
1974
 
      sql_print_error("Error while loading time zone description from "
1975
 
                      "mysql.time_zone_transition table: "
1976
 
                      "too much transitions");
1977
 
      goto end;
1978
 
    }
1979
 
    if (ttid + 1 > tz_info->typecnt)
1980
 
    {
1981
 
      sql_print_error("Error while loading time zone description from "
1982
 
                      "mysql.time_zone_transition table: "
1983
 
                      "bad transition type id");
1984
 
      goto end;
1985
 
    }
1986
 
 
1987
 
    ats[tz_info->timecnt]= ttime;
1988
 
    types[tz_info->timecnt]= ttid;
1989
 
    tz_info->timecnt++;
1990
 
 
1991
 
 
1992
 
    res= table->file->index_next_same(table->record[0],
1993
 
                                      table->field[0]->ptr, 4);
1994
 
  }
1995
 
 
1996
 
  /*
1997
 
    We have to allow HA_ERR_KEY_NOT_FOUND because some time zones
1998
 
    for example UTC have no transitons.
1999
 
  */
2000
 
  if (res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
2001
 
  {
2002
 
    sql_print_error("Error while loading time zone description from "
2003
 
                    "mysql.time_zone_transition table");
2004
 
    goto end;
2005
 
  }
2006
 
 
2007
 
  (void)table->file->ha_index_end();
2008
 
  table= 0;
2009
 
 
2010
 
  /*
2011
 
    Now we will allocate memory and init TIME_ZONE_INFO structure.
2012
 
  */
2013
 
  if (!(alloc_buff= (char*) alloc_root(&tz_storage,
2014
 
                                       ALIGN_SIZE(sizeof(my_time_t) *
2015
 
                                                  tz_info->timecnt) +
2016
 
                                       ALIGN_SIZE(tz_info->timecnt) +
2017
 
#ifdef ABBR_ARE_USED
2018
 
                                       ALIGN_SIZE(tz_info->charcnt) +
2019
 
#endif
2020
 
                                       sizeof(TRAN_TYPE_INFO) *
2021
 
                                       tz_info->typecnt)))
2022
 
  {
2023
 
    sql_print_error("Out of memory while loading time zone description");
2024
 
    goto end;
2025
 
  }
2026
 
 
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);
2037
 
#endif
2038
 
  tz_info->ttis= (TRAN_TYPE_INFO *)alloc_buff;
2039
 
  memcpy(tz_info->ttis, ttis, tz_info->typecnt * sizeof(TRAN_TYPE_INFO));
2040
 
 
2041
 
  /*
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.
2044
 
  */
2045
 
  if (tz_info->typecnt < 1)
2046
 
  {
2047
 
    sql_print_error("loading time zone without transition types");
2048
 
    goto end;
2049
 
  }
2050
 
  if (prepare_tz_info(tz_info, &tz_storage))
2051
 
  {
2052
 
    sql_print_error("Unable to build mktime map for time zone");
2053
 
    goto end;
2054
 
  }
2055
 
 
2056
 
 
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)))
2063
 
  {
2064
 
    sql_print_error("Out of memory while loading time zone");
2065
 
    goto end;
2066
 
  }
2067
 
 
2068
 
  /*
2069
 
    Loading of time zone succeeded
2070
 
  */
2071
 
  return_val= tmp_tzname->tz;
2072
 
 
2073
 
end:
2074
 
 
2075
 
  if (table)
2076
 
    (void)table->file->ha_index_end();
2077
 
 
2078
 
  return(return_val);
2079
1082
}
2080
1083
 
2081
1084
 
2162
1165
/*
2163
1166
  Get Time_zone object for specified time zone.
2164
1167
 
2165
 
  SYNOPSIS
2166
 
    my_tz_find()
2167
 
      thd  - pointer to thread THD structure
2168
 
      name - time zone specification
2169
 
 
2170
 
  DESCRIPTION
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
2175
 
    Time_zone object.
2176
 
 
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.
2180
 
 
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).
2185
 
 
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).
2189
 
 
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
2193
 
    server start up.
2194
 
 
2195
 
  RETURN VALUE
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.
2198
1169
 
2199
1170
*/
2200
1171
Time_zone *
2201
1172
my_tz_find(THD *thd, const String *name)
2202
1173
{
2203
 
  Tz_names_entry *tmp_tzname;
2204
 
  Time_zone *result_tz= 0;
2205
 
  long offset;
2206
 
 
2207
 
  if (!name)
2208
 
    return(0);
2209
 
 
2210
 
  VOID(pthread_mutex_lock(&tz_LOCK));
2211
 
 
2212
 
  if (!str_to_offset(name->ptr(), name->length(), &offset))
2213
 
  {
2214
 
 
2215
 
    if (!(result_tz= (Time_zone_offset *)hash_search(&offset_tzs,
2216
 
                                                     (const uchar *)&offset,
2217
 
                                                     sizeof(long))))
2218
 
    {
2219
 
 
2220
 
      if (!(result_tz= new (&tz_storage) Time_zone_offset(offset)) ||
2221
 
          my_hash_insert(&offset_tzs, (const uchar *) result_tz))
2222
 
      {
2223
 
        result_tz= 0;
2224
 
        sql_print_error("Fatal error: Out of memory "
2225
 
                        "while setting new time zone");
2226
 
      }
2227
 
    }
2228
 
  }
2229
 
  else
2230
 
  {
2231
 
    result_tz= 0;
2232
 
    if ((tmp_tzname= (Tz_names_entry *)hash_search(&tz_names,
2233
 
                                                   (const uchar *)name->ptr(),
2234
 
                                                   name->length())))
2235
 
      result_tz= tmp_tzname->tz;
2236
 
    else if (time_zone_tables_exist)
2237
 
    {
2238
 
      TABLE_LIST tz_tables[MY_TZ_TABLES_COUNT];
2239
 
      Open_tables_state open_tables_state_backup;
2240
 
 
2241
 
      tz_init_table_list(tz_tables);
2242
 
      if (!open_system_tables_for_read(thd, tz_tables,
2243
 
                                       &open_tables_state_backup))
2244
 
      {
2245
 
        result_tz= tz_load_from_open_tables(name, tz_tables);
2246
 
        close_system_tables(thd, &open_tables_state_backup);
2247
 
      }
2248
 
    }
2249
 
  }
2250
 
 
2251
 
  VOID(pthread_mutex_unlock(&tz_LOCK));
2252
 
 
2253
 
  return(result_tz);
2254
 
}
2255
 
 
2256
 
 
2257
 
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
2258
 
 
2259
 
 
2260
 
#ifdef TZINFO2SQL
2261
 
/*
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
2264
 
  tables.
2265
 
*/
2266
 
 
2267
 
 
2268
 
/*
2269
 
  Print info about time zone described by TIME_ZONE_INFO struct as
2270
 
  SQL statements populating mysql.time_zone* tables.
2271
 
 
2272
 
  SYNOPSIS
2273
 
    print_tz_as_sql()
2274
 
      tz_name - name of time zone
2275
 
      sp      - structure describing time zone
2276
 
*/
2277
 
void
2278
 
print_tz_as_sql(const char* tz_name, const TIME_ZONE_INFO *sp)
2279
 
{
2280
 
  uint i;
2281
 
 
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);
2288
 
 
2289
 
  if (sp->timecnt)
2290
 
  {
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]);
2296
 
    printf(";\n");
2297
 
  }
2298
 
 
2299
 
  printf("INSERT INTO time_zone_transition_type \
2300
 
(Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES\n");
2301
 
 
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);
2306
 
  printf(";\n");
2307
 
}
2308
 
 
2309
 
 
2310
 
/*
2311
 
  Print info about leap seconds in time zone as SQL statements
2312
 
  populating mysql.time_zone_leap_second table.
2313
 
 
2314
 
  SYNOPSIS
2315
 
    print_tz_leaps_as_sql()
2316
 
      sp      - structure describing time zone
2317
 
*/
2318
 
void
2319
 
print_tz_leaps_as_sql(const TIME_ZONE_INFO *sp)
2320
 
{
2321
 
  uint i;
2322
 
 
2323
 
  /*
2324
 
    We are assuming that there are only one list of leap seconds
2325
 
    For all timezones.
2326
 
  */
2327
 
  printf("TRUNCATE TABLE time_zone_leap_second;\n");
2328
 
 
2329
 
  if (sp->leapcnt)
2330
 
  {
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);
2336
 
    printf(";\n");
2337
 
  }
2338
 
 
2339
 
  printf("ALTER TABLE time_zone_leap_second ORDER BY Transition_time;\n");
2340
 
}
2341
 
 
2342
 
 
2343
 
/*
2344
 
  Some variables used as temporary or as parameters
2345
 
  in recursive scan_tz_dir() code.
2346
 
*/
2347
 
TIME_ZONE_INFO tz_info;
2348
 
MEM_ROOT tz_storage;
2349
 
char fullname[FN_REFLEN + 1];
2350
 
char *root_name_end;
2351
 
 
2352
 
 
2353
 
/*
2354
 
  Recursively scan zoneinfo directory and print all found time zone
2355
 
  descriptions as SQL.
2356
 
 
2357
 
  SYNOPSIS
2358
 
    scan_tz_dir()
2359
 
      name_end - pointer to end of path to directory to be searched.
2360
 
 
2361
 
  DESCRIPTION
2362
 
    This auxiliary recursive function also uses several global
2363
 
    variables as in parameters and for storing temporary values.
2364
 
 
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
2369
 
 
2370
 
  RETURN VALUE
2371
 
    0 - Ok, 1 - Fatal error
2372
 
 
2373
 
*/
2374
 
my_bool
2375
 
scan_tz_dir(char * name_end)
2376
 
{
2377
 
  MY_DIR *cur_dir;
2378
 
  char *name_end_tmp;
2379
 
  uint i;
2380
 
 
2381
 
  if (!(cur_dir= my_dir(fullname, MYF(MY_WANT_STAT))))
2382
 
    return 1;
2383
 
 
2384
 
  name_end= strmake(name_end, "/", FN_REFLEN - (name_end - fullname));
2385
 
 
2386
 
  for (i= 0; i < cur_dir->number_off_files; i++)
2387
 
  {
2388
 
    if (cur_dir->dir_entry[i].name[0] != '.')
2389
 
    {
2390
 
      name_end_tmp= strmake(name_end, cur_dir->dir_entry[i].name,
2391
 
                            FN_REFLEN - (name_end - fullname));
2392
 
 
2393
 
      if (MY_S_ISDIR(cur_dir->dir_entry[i].mystat->st_mode))
2394
 
      {
2395
 
        if (scan_tz_dir(name_end_tmp))
2396
 
        {
2397
 
          my_dirend(cur_dir);
2398
 
          return 1;
2399
 
        }
2400
 
      }
2401
 
      else if (MY_S_ISREG(cur_dir->dir_entry[i].mystat->st_mode))
2402
 
      {
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);
2406
 
        else
2407
 
          fprintf(stderr,
2408
 
                  "Warning: Unable to load '%s' as time zone. Skipping it.\n",
2409
 
                  fullname);
2410
 
        free_root(&tz_storage, MYF(0));
2411
 
      }
2412
 
      else
2413
 
        fprintf(stderr, "Warning: '%s' is not regular file or directory\n",
2414
 
                fullname);
2415
 
    }
2416
 
  }
2417
 
 
2418
 
  my_dirend(cur_dir);
2419
 
 
2420
 
  return 0;
2421
 
}
2422
 
 
2423
 
 
2424
 
int
2425
 
main(int argc, char **argv)
2426
 
{
2427
 
  MY_INIT(argv[0]);
2428
 
 
2429
 
  if (argc != 2 && argc != 3)
2430
 
  {
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]);
2435
 
    return 1;
2436
 
  }
2437
 
 
2438
 
  if (argc == 2)
2439
 
  {
2440
 
    root_name_end= strmake(fullname, argv[1], FN_REFLEN);
2441
 
 
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");
2446
 
 
2447
 
    if (scan_tz_dir(root_name_end))
2448
 
    {
2449
 
      fprintf(stderr, "There were fatal errors during processing "
2450
 
                      "of zoneinfo directory\n");
2451
 
      return 1;
2452
 
    }
2453
 
 
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");
2458
 
  }
2459
 
  else
2460
 
  {
2461
 
    init_alloc_root(&tz_storage, 32768, 0);
2462
 
 
2463
 
    if (strcmp(argv[1], "--leap") == 0)
2464
 
    {
2465
 
      if (tz_load(argv[2], &tz_info, &tz_storage))
2466
 
      {
2467
 
        fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[2]);
2468
 
        return 1;
2469
 
      }
2470
 
      print_tz_leaps_as_sql(&tz_info);
2471
 
    }
2472
 
    else
2473
 
    {
2474
 
      if (tz_load(argv[1], &tz_info, &tz_storage))
2475
 
      {
2476
 
        fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[2]);
2477
 
        return 1;
2478
 
      }
2479
 
      print_tz_as_sql(argv[2], &tz_info);
2480
 
    }
2481
 
 
2482
 
    free_root(&tz_storage, MYF(0));
2483
 
  }
2484
 
 
2485
 
  return 0;
2486
 
}
2487
 
 
2488
 
#endif /* defined(TZINFO2SQL) */
2489
 
 
2490
 
 
2491
 
#ifdef TESTTIME
2492
 
 
2493
 
/*
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
2496
 
   implementation.
2497
 
*/
2498
 
 
2499
 
#ifndef CHAR_BIT
2500
 
#define CHAR_BIT 8
2501
 
#endif
2502
 
 
2503
 
#ifndef TYPE_BIT
2504
 
#define TYPE_BIT(type)  (sizeof (type) * CHAR_BIT)
2505
 
#endif
2506
 
 
2507
 
#ifndef TYPE_SIGNED
2508
 
#define TYPE_SIGNED(type) (((type) -1) < 0)
2509
 
#endif
2510
 
 
2511
 
my_bool
2512
 
is_equal_TIME_tm(const TIME* time_arg, const struct tm * tm_arg)
2513
 
{
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;
2521
 
}
2522
 
 
2523
 
 
2524
 
int
2525
 
main(int argc, char **argv)
2526
 
{
2527
 
  my_bool localtime_negative;
2528
 
  TIME_ZONE_INFO tz_info;
2529
 
  struct tm tmp;
2530
 
  MYSQL_TIME time_tmp;
2531
 
  time_t t, t1, t2;
2532
 
  char fullname[FN_REFLEN+1];
2533
 
  char *str_end;
2534
 
  MEM_ROOT tz_storage;
2535
 
 
2536
 
  MY_INIT(argv[0]);
2537
 
 
2538
 
  init_alloc_root(&tz_storage, 32768, 0);
2539
 
 
2540
 
  /* let us set some well known timezone */
2541
 
  setenv("TZ", "MET", 1);
2542
 
  tzset();
2543
 
 
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))
2548
 
  {
2549
 
    t= -100;
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);
2556
 
 
2557
 
    printf("mktime %s negative results (%d)\n",
2558
 
           (t == mktime(&tmp) ? "doesn't support" : "supports"),
2559
 
           (int)mktime(&tmp));
2560
 
  }
2561
 
 
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;
2564
 
  t= mktime(&tmp);
2565
 
  printf("mktime returns %s for spring time gap (%d)\n",
2566
 
         (t != (time_t)-1 ? "something" : "error"), (int)t);
2567
 
 
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;
2570
 
  t= mktime(&tmp);
2571
 
  printf("mktime returns %s for non existing date (%d)\n",
2572
 
         (t != (time_t)-1 ? "something" : "error"), (int)t);
2573
 
 
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;
2576
 
  t= mktime(&tmp);
2577
 
  printf("mktime %s unnormalized input (%d)\n",
2578
 
         (t != (time_t)-1 ? "handles" : "doesn't handle"), (int)t);
2579
 
 
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;
2582
 
  mktime(&tmp);
2583
 
  tmp.tm_hour= 2; tmp.tm_isdst= -1;
2584
 
  t= mktime(&tmp);
2585
 
  tmp.tm_hour= 4; tmp.tm_isdst= 0;
2586
 
  mktime(&tmp);
2587
 
  tmp.tm_hour= 2; tmp.tm_isdst= -1;
2588
 
  t1= mktime(&tmp);
2589
 
  printf("mktime is %s (%d %d)\n",
2590
 
         (t == t1 ? "determenistic" : "is non-determenistic"),
2591
 
         (int)t, (int)t1);
2592
 
 
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));
2596
 
 
2597
 
  if (tz_load(fullname, &tz_info, &tz_storage))
2598
 
  {
2599
 
    printf("Unable to load time zone info from '%s'\n", fullname);
2600
 
    free_root(&tz_storage, MYF(0));
2601
 
    return 1;
2602
 
  }
2603
 
 
2604
 
  printf("Testing our implementation\n");
2605
 
 
2606
 
  if (TYPE_SIGNED(time_t) && localtime_negative)
2607
 
  {
2608
 
    for (t= -40000; t < 20000; t++)
2609
 
    {
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))
2613
 
      {
2614
 
        printf("Problem with negative time_t = %d\n", (int)t);
2615
 
        free_root(&tz_storage, MYF(0));
2616
 
        return 1;
2617
 
      }
2618
 
    }
2619
 
    printf("gmt_sec_to_TIME = localtime for time_t in [-40000,20000) range\n");
2620
 
  }
2621
 
 
2622
 
  for (t= 1000000000; t < 1100000000; t+= 13)
2623
 
  {
2624
 
    localtime_r(&t,&tmp);
2625
 
    gmt_sec_to_TIME(&time_tmp, (my_time_t)t, &tz_info);
2626
 
 
2627
 
    if (!is_equal_TIME_tm(&time_tmp, &tmp))
2628
 
    {
2629
 
      printf("Problem with time_t = %d\n", (int)t);
2630
 
      free_root(&tz_storage, MYF(0));
2631
 
      return 1;
2632
 
    }
2633
 
  }
2634
 
  printf("gmt_sec_to_TIME = localtime for time_t in [1000000000,1100000000) range\n");
2635
 
 
2636
 
  init_time();
2637
 
 
2638
 
  /*
2639
 
    Be careful here! my_system_gmt_sec doesn't fully handle unnormalized
2640
 
    dates.
2641
 
  */
2642
 
  for (time_tmp.year= 1980; time_tmp.year < 2010; time_tmp.year++)
2643
 
  {
2644
 
    for (time_tmp.month= 1; time_tmp.month < 13; time_tmp.month++)
2645
 
    {
2646
 
      for (time_tmp.day= 1;
2647
 
           time_tmp.day < mon_lengths[isleap(time_tmp.year)][time_tmp.month-1];
2648
 
           time_tmp.day++)
2649
 
      {
2650
 
        for (time_tmp.hour= 0; time_tmp.hour < 24; time_tmp.hour++)
2651
 
        {
2652
 
          for (time_tmp.minute= 0; time_tmp.minute < 60; time_tmp.minute+= 5)
2653
 
          {
2654
 
            for (time_tmp.second=0; time_tmp.second<60; time_tmp.second+=25)
2655
 
            {
2656
 
              long not_used;
2657
 
              my_bool not_used_2;
2658
 
              t= (time_t)my_system_gmt_sec(&time_tmp, &not_used, &not_used_2);
2659
 
              t1= (time_t)TIME_to_gmt_sec(&time_tmp, &tz_info, &not_used_2);
2660
 
              if (t != t1)
2661
 
              {
2662
 
                /*
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 !!!
2666
 
                */
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;
2673
 
                tmp.tm_isdst= 1;
2674
 
 
2675
 
                t2= mktime(&tmp);
2676
 
 
2677
 
                if (t1 == t2)
2678
 
                  continue;
2679
 
 
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,
2683
 
                       (int)t,(int)t1);
2684
 
 
2685
 
                free_root(&tz_storage, MYF(0));
2686
 
                return 1;
2687
 
              }
2688
 
            }
2689
 
          }
2690
 
        }
2691
 
      }
2692
 
    }
2693
 
  }
2694
 
 
2695
 
  printf("TIME_to_gmt_sec = my_system_gmt_sec for test range\n");
2696
 
 
2697
 
  free_root(&tz_storage, MYF(0));
2698
 
  return 0;
2699
 
}
2700
 
 
2701
 
#endif /* defined(TESTTIME) */
 
1174
  return NULL;
 
1175
}