~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/my_time.cc

  • Committer: Stewart Smith
  • Date: 2008-11-21 16:06:07 UTC
  • mto: This revision was merged to the branch mainline in revision 593.
  • Revision ID: stewart@flamingspork.com-20081121160607-n6gdlt013spuo54r
remove mysql_frm_type
and fix engines to return correct value from delete_table when table doesn't exist.
(it should be ENOENT).

Also fix up some tests that manipulated frm files by hand. These tests are no longer valid and will need to be rewritten in the not too distant future.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2004-2006 MySQL AB
 
2
 
 
3
 This program is free software; you can redistribute it and/or modify
 
4
 it under the terms of the GNU General Public License as published by
 
5
 the Free Software Foundation; version 2 of the License.
 
6
 
 
7
 This program is distributed in the hope that it will be useful,
 
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
 GNU General Public License for more details.
 
11
 
 
12
 You should have received a copy of the GNU General Public License
 
13
 along with this program; if not, write to the Free Software
 
14
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
#include <my_time.h>
 
17
#include <mystrings/m_string.h>
 
18
#include <mystrings/m_ctype.h>
 
19
#include <drizzled/util/test.h>
 
20
/* Windows version of localtime_r() is declared in my_ptrhead.h */
 
21
 
 
22
uint64_t log_10_int[20]=
 
23
{
 
24
  1, 10, 100, 1000, 10000UL, 100000UL, 1000000UL, 10000000UL,
 
25
  100000000ULL, 1000000000ULL, 10000000000ULL, 100000000000ULL,
 
26
  1000000000000ULL, 10000000000000ULL, 100000000000000ULL,
 
27
  1000000000000000ULL, 10000000000000000ULL, 100000000000000000ULL,
 
28
  1000000000000000000ULL, 10000000000000000000ULL
 
29
};
 
30
 
 
31
 
 
32
/* Position for YYYY-DD-MM HH-MM-DD.FFFFFF AM in default format */
 
33
 
 
34
static unsigned char internal_format_positions[]=
 
35
{0, 1, 2, 3, 4, 5, 6, (unsigned char) 255};
 
36
 
 
37
static char time_separator=':';
 
38
 
 
39
static uint32_t const days_at_timestart=719528; /* daynr at 1970.01.01 */
 
40
unsigned char days_in_month[]= {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
 
41
 
 
42
/*
 
43
  Offset of system time zone from UTC in seconds used to speed up 
 
44
  work of my_system_gmt_sec() function.
 
45
*/
 
46
static long my_time_zone=0;
 
47
 
 
48
 
 
49
/* Calc days in one year. works with 0 <= year <= 99 */
 
50
 
 
51
uint32_t calc_days_in_year(uint32_t year)
 
52
{
 
53
  return ((year & 3) == 0 && (year%100 || (year%400 == 0 && year)) ?
 
54
          366 : 365);
 
55
}
 
56
 
 
57
/**
 
58
  @brief Check datetime value for validity according to flags.
 
59
 
 
60
  @param[in]  ltime          Date to check.
 
61
  @param[in]  not_zero_date  ltime is not the zero date
 
62
  @param[in]  flags          flags to check
 
63
                             (see str_to_datetime() flags in my_time.h)
 
64
  @param[out] was_cut        set to 2 if value was invalid according to flags.
 
65
                             (Feb 29 in non-leap etc.)  This remains unchanged
 
66
                             if value is not invalid.
 
67
 
 
68
  @details Here we assume that year and month is ok!
 
69
    If month is 0 we allow any date. (This only happens if we allow zero
 
70
    date parts in str_to_datetime())
 
71
    Disallow dates with zero year and non-zero month and/or day.
 
72
 
 
73
  @return
 
74
    0  OK
 
75
    1  error
 
76
*/
 
77
 
 
78
bool check_date(const DRIZZLE_TIME *ltime, bool not_zero_date,
 
79
                   uint32_t flags, int *was_cut)
 
80
{
 
81
  if (not_zero_date)
 
82
  {
 
83
    if ((((flags & TIME_NO_ZERO_IN_DATE) || !(flags & TIME_FUZZY_DATE)) &&
 
84
         (ltime->month == 0 || ltime->day == 0)) ||
 
85
        (!(flags & TIME_INVALID_DATES) &&
 
86
         ltime->month && ltime->day > days_in_month[ltime->month-1] &&
 
87
         (ltime->month != 2 || calc_days_in_year(ltime->year) != 366 ||
 
88
          ltime->day != 29)))
 
89
    {
 
90
      *was_cut= 2;
 
91
      return true;
 
92
    }
 
93
  }
 
94
  else if (flags & TIME_NO_ZERO_DATE)
 
95
  {
 
96
    /*
 
97
      We don't set *was_cut here to signal that the problem was a zero date
 
98
      and not an invalid date
 
99
    */
 
100
    return true;
 
101
  }
 
102
  return false;
 
103
}
 
104
 
 
105
 
 
106
/*
 
107
  Convert a timestamp string to a DRIZZLE_TIME value.
 
108
 
 
109
  SYNOPSIS
 
110
    str_to_datetime()
 
111
    str                 String to parse
 
112
    length              Length of string
 
113
    l_time              Date is stored here
 
114
    flags               Bitmap of following items
 
115
                        TIME_FUZZY_DATE    Set if we should allow partial dates
 
116
                        TIME_DATETIME_ONLY Set if we only allow full datetimes.
 
117
                        TIME_NO_ZERO_IN_DATE    Don't allow partial dates
 
118
                        TIME_NO_ZERO_DATE       Don't allow 0000-00-00 date
 
119
                        TIME_INVALID_DATES      Allow 2000-02-31
 
120
    was_cut             0       Value OK
 
121
                        1       If value was cut during conversion
 
122
                        2       check_date(date,flags) considers date invalid
 
123
 
 
124
  DESCRIPTION
 
125
    At least the following formats are recogniced (based on number of digits)
 
126
    YYMMDD, YYYYMMDD, YYMMDDHHMMSS, YYYYMMDDHHMMSS
 
127
    YY-MM-DD, YYYY-MM-DD, YY-MM-DD HH.MM.SS
 
128
    YYYYMMDDTHHMMSS  where T is a the character T (ISO8601)
 
129
    Also dates where all parts are zero are allowed
 
130
 
 
131
    The second part may have an optional .###### fraction part.
 
132
 
 
133
  NOTES
 
134
   This function should work with a format position vector as long as the
 
135
   following things holds:
 
136
   - All date are kept together and all time parts are kept together
 
137
   - Date and time parts must be separated by blank
 
138
   - Second fractions must come after second part and be separated
 
139
     by a '.'.  (The second fractions are optional)
 
140
   - AM/PM must come after second fractions (or after seconds if no fractions)
 
141
   - Year must always been specified.
 
142
   - If time is before date, then we will use datetime format only if
 
143
     the argument consist of two parts, separated by space.
 
144
     Otherwise we will assume the argument is a date.
 
145
   - The hour part must be specified in hour-minute-second order.
 
146
 
 
147
  RETURN VALUES
 
148
    DRIZZLE_TIMESTAMP_NONE        String wasn't a timestamp, like
 
149
                                [DD [HH:[MM:[SS]]]].fraction.
 
150
                                l_time is not changed.
 
151
    DRIZZLE_TIMESTAMP_DATE        DATE string (YY MM and DD parts ok)
 
152
    DRIZZLE_TIMESTAMP_DATETIME    Full timestamp
 
153
    DRIZZLE_TIMESTAMP_ERROR       Timestamp with wrong values.
 
154
                                All elements in l_time is set to 0
 
155
*/
 
156
 
 
157
#define MAX_DATE_PARTS 8
 
158
 
 
159
enum enum_drizzle_timestamp_type
 
160
str_to_datetime(const char *str, uint32_t length, DRIZZLE_TIME *l_time,
 
161
                uint32_t flags, int *was_cut)
 
162
{
 
163
  uint32_t field_length, year_length=4, digits, i, number_of_fields;
 
164
  uint32_t date[MAX_DATE_PARTS], date_len[MAX_DATE_PARTS];
 
165
  uint32_t add_hours= 0, start_loop;
 
166
  uint32_t not_zero_date, allow_space;
 
167
  bool is_internal_format;
 
168
  const char *pos, *last_field_pos=NULL;
 
169
  const char *end=str+length;
 
170
  const unsigned char *format_position;
 
171
  bool found_delimitier= 0, found_space= 0;
 
172
  uint32_t frac_pos, frac_len;
 
173
 
 
174
  *was_cut= 0;
 
175
 
 
176
  /* Skip space at start */
 
177
  for (; str != end && my_isspace(&my_charset_utf8_general_ci, *str) ; str++)
 
178
    ;
 
179
  if (str == end || ! my_isdigit(&my_charset_utf8_general_ci, *str))
 
180
  {
 
181
    *was_cut= 1;
 
182
    return(DRIZZLE_TIMESTAMP_NONE);
 
183
  }
 
184
 
 
185
  is_internal_format= 0;
 
186
  /* This has to be changed if want to activate different timestamp formats */
 
187
  format_position= internal_format_positions;
 
188
 
 
189
  /*
 
190
    Calculate number of digits in first part.
 
191
    If length= 8 or >= 14 then year is of format YYYY.
 
192
    (YYYY-MM-DD,  YYYYMMDD, YYYYYMMDDHHMMSS)
 
193
  */
 
194
  for (pos=str;
 
195
       pos != end && (my_isdigit(&my_charset_utf8_general_ci,*pos) || *pos == 'T');
 
196
       pos++)
 
197
    ;
 
198
 
 
199
  digits= (uint) (pos-str);
 
200
  start_loop= 0;                                /* Start of scan loop */
 
201
  date_len[format_position[0]]= 0;              /* Length of year field */
 
202
  if (pos == end || *pos == '.')
 
203
  {
 
204
    /* Found date in internal format (only numbers like YYYYMMDD) */
 
205
    year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
 
206
    field_length= year_length;
 
207
    is_internal_format= 1;
 
208
    format_position= internal_format_positions;
 
209
  }
 
210
  else
 
211
  {
 
212
    if (format_position[0] >= 3)                /* If year is after HHMMDD */
 
213
    {
 
214
      /*
 
215
        If year is not in first part then we have to determinate if we got
 
216
        a date field or a datetime field.
 
217
        We do this by checking if there is two numbers separated by
 
218
        space in the input.
 
219
      */
 
220
      while (pos < end && !my_isspace(&my_charset_utf8_general_ci, *pos))
 
221
        pos++;
 
222
      while (pos < end && !my_isdigit(&my_charset_utf8_general_ci, *pos))
 
223
        pos++;
 
224
      if (pos == end)
 
225
      {
 
226
        if (flags & TIME_DATETIME_ONLY)
 
227
        {
 
228
          *was_cut= 1;
 
229
          return(DRIZZLE_TIMESTAMP_NONE);   /* Can't be a full datetime */
 
230
        }
 
231
        /* Date field.  Set hour, minutes and seconds to 0 */
 
232
        date[0]= date[1]= date[2]= date[3]= date[4]= 0;
 
233
        start_loop= 5;                         /* Start with first date part */
 
234
      }
 
235
    }
 
236
 
 
237
    field_length= format_position[0] == 0 ? 4 : 2;
 
238
  }
 
239
 
 
240
  /*
 
241
    Only allow space in the first "part" of the datetime field and:
 
242
    - after days, part seconds
 
243
    - before and after AM/PM (handled by code later)
 
244
 
 
245
    2003-03-03 20:00:20 AM
 
246
    20:00:20.000000 AM 03-03-2000
 
247
  */
 
248
  i= cmax((uint) format_position[0], (uint) format_position[1]);
 
249
  set_if_bigger(i, (uint) format_position[2]);
 
250
  allow_space= ((1 << i) | (1 << format_position[6]));
 
251
  allow_space&= (1 | 2 | 4 | 8);
 
252
 
 
253
  not_zero_date= 0;
 
254
  for (i = start_loop;
 
255
       i < MAX_DATE_PARTS-1 && str != end &&
 
256
         my_isdigit(&my_charset_utf8_general_ci,*str);
 
257
       i++)
 
258
  {
 
259
    const char *start= str;
 
260
    uint32_t tmp_value= (uint) (unsigned char) (*str++ - '0');
 
261
    while (str != end && my_isdigit(&my_charset_utf8_general_ci,str[0]) &&
 
262
           (!is_internal_format || --field_length))
 
263
    {
 
264
      tmp_value=tmp_value*10 + (uint32_t) (unsigned char) (*str - '0');
 
265
      str++;
 
266
    }
 
267
    date_len[i]= (uint) (str - start);
 
268
    if (tmp_value > 999999)                     /* Impossible date part */
 
269
    {
 
270
      *was_cut= 1;
 
271
      return(DRIZZLE_TIMESTAMP_NONE);
 
272
    }
 
273
    date[i]=tmp_value;
 
274
    not_zero_date|= tmp_value;
 
275
 
 
276
    /* Length of next field */
 
277
    field_length= format_position[i+1] == 0 ? 4 : 2;
 
278
 
 
279
    if ((last_field_pos= str) == end)
 
280
    {
 
281
      i++;                                      /* Register last found part */
 
282
      break;
 
283
    }
 
284
    /* Allow a 'T' after day to allow CCYYMMDDT type of fields */
 
285
    if (i == format_position[2] && *str == 'T')
 
286
    {
 
287
      str++;                                    /* ISO8601:  CCYYMMDDThhmmss */
 
288
      continue;
 
289
    }
 
290
    if (i == format_position[5])                /* Seconds */
 
291
    {
 
292
      if (*str == '.')                          /* Followed by part seconds */
 
293
      {
 
294
        str++;
 
295
        field_length= 6;                        /* 6 digits */
 
296
      }
 
297
      continue;
 
298
    }
 
299
    while (str != end &&
 
300
           (my_ispunct(&my_charset_utf8_general_ci,*str) ||
 
301
            my_isspace(&my_charset_utf8_general_ci,*str)))
 
302
    {
 
303
      if (my_isspace(&my_charset_utf8_general_ci,*str))
 
304
      {
 
305
        if (!(allow_space & (1 << i)))
 
306
        {
 
307
          *was_cut= 1;
 
308
          return(DRIZZLE_TIMESTAMP_NONE);
 
309
        }
 
310
        found_space= 1;
 
311
      }
 
312
      str++;
 
313
      found_delimitier= 1;                      /* Should be a 'normal' date */
 
314
    }
 
315
    /* Check if next position is AM/PM */
 
316
    if (i == format_position[6])                /* Seconds, time for AM/PM */
 
317
    {
 
318
      i++;                                      /* Skip AM/PM part */
 
319
      if (format_position[7] != 255)            /* If using AM/PM */
 
320
      {
 
321
        if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
 
322
        {
 
323
          if (str[0] == 'p' || str[0] == 'P')
 
324
            add_hours= 12;
 
325
          else if (str[0] != 'a' || str[0] != 'A')
 
326
            continue;                           /* Not AM/PM */
 
327
          str+= 2;                              /* Skip AM/PM */
 
328
          /* Skip space after AM/PM */
 
329
          while (str != end && my_isspace(&my_charset_utf8_general_ci,*str))
 
330
            str++;
 
331
        }
 
332
      }
 
333
    }
 
334
    last_field_pos= str;
 
335
  }
 
336
  if (found_delimitier && !found_space && (flags & TIME_DATETIME_ONLY))
 
337
  {
 
338
    *was_cut= 1;
 
339
    return(DRIZZLE_TIMESTAMP_NONE);          /* Can't be a datetime */
 
340
  }
 
341
 
 
342
  str= last_field_pos;
 
343
 
 
344
  number_of_fields= i - start_loop;
 
345
  while (i < MAX_DATE_PARTS)
 
346
  {
 
347
    date_len[i]= 0;
 
348
    date[i++]= 0;
 
349
  }
 
350
 
 
351
  if (!is_internal_format)
 
352
  {
 
353
    year_length= date_len[(uint) format_position[0]];
 
354
    if (!year_length)                           /* Year must be specified */
 
355
    {
 
356
      *was_cut= 1;
 
357
      return(DRIZZLE_TIMESTAMP_NONE);
 
358
    }
 
359
 
 
360
    l_time->year=               date[(uint) format_position[0]];
 
361
    l_time->month=              date[(uint) format_position[1]];
 
362
    l_time->day=                date[(uint) format_position[2]];
 
363
    l_time->hour=               date[(uint) format_position[3]];
 
364
    l_time->minute=             date[(uint) format_position[4]];
 
365
    l_time->second=             date[(uint) format_position[5]];
 
366
 
 
367
    frac_pos= (uint) format_position[6];
 
368
    frac_len= date_len[frac_pos];
 
369
    if (frac_len < 6)
 
370
      date[frac_pos]*= (uint) log_10_int[6 - frac_len];
 
371
    l_time->second_part= date[frac_pos];
 
372
 
 
373
    if (format_position[7] != (unsigned char) 255)
 
374
    {
 
375
      if (l_time->hour > 12)
 
376
      {
 
377
        *was_cut= 1;
 
378
        goto err;
 
379
      }
 
380
      l_time->hour= l_time->hour%12 + add_hours;
 
381
    }
 
382
  }
 
383
  else
 
384
  {
 
385
    l_time->year=       date[0];
 
386
    l_time->month=      date[1];
 
387
    l_time->day=        date[2];
 
388
    l_time->hour=       date[3];
 
389
    l_time->minute=     date[4];
 
390
    l_time->second=     date[5];
 
391
    if (date_len[6] < 6)
 
392
      date[6]*= (uint) log_10_int[6 - date_len[6]];
 
393
    l_time->second_part=date[6];
 
394
  }
 
395
  l_time->neg= 0;
 
396
 
 
397
  if (year_length == 2 && not_zero_date)
 
398
    l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);
 
399
 
 
400
  if (number_of_fields < 3 ||
 
401
      l_time->year > 9999 || l_time->month > 12 ||
 
402
      l_time->day > 31 || l_time->hour > 23 ||
 
403
      l_time->minute > 59 || l_time->second > 59)
 
404
  {
 
405
    /* Only give warning for a zero date if there is some garbage after */
 
406
    if (!not_zero_date)                         /* If zero date */
 
407
    {
 
408
      for (; str != end ; str++)
 
409
      {
 
410
        if (!my_isspace(&my_charset_utf8_general_ci, *str))
 
411
        {
 
412
          not_zero_date= 1;                     /* Give warning */
 
413
          break;
 
414
        }
 
415
      }
 
416
    }
 
417
    *was_cut= test(not_zero_date);
 
418
    goto err;
 
419
  }
 
420
 
 
421
  if (check_date(l_time, not_zero_date != 0, flags, was_cut))
 
422
    goto err;
 
423
 
 
424
  l_time->time_type= (number_of_fields <= 3 ?
 
425
                      DRIZZLE_TIMESTAMP_DATE : DRIZZLE_TIMESTAMP_DATETIME);
 
426
 
 
427
  for (; str != end ; str++)
 
428
  {
 
429
    if (!my_isspace(&my_charset_utf8_general_ci,*str))
 
430
    {
 
431
      *was_cut= 1;
 
432
      break;
 
433
    }
 
434
  }
 
435
 
 
436
  return(l_time->time_type=
 
437
              (number_of_fields <= 3 ? DRIZZLE_TIMESTAMP_DATE :
 
438
                                       DRIZZLE_TIMESTAMP_DATETIME));
 
439
 
 
440
err:
 
441
  memset(l_time, 0, sizeof(*l_time));
 
442
  return(DRIZZLE_TIMESTAMP_ERROR);
 
443
}
 
444
 
 
445
 
 
446
/*
 
447
 Convert a time string to a DRIZZLE_TIME struct.
 
448
 
 
449
  SYNOPSIS
 
450
   str_to_time()
 
451
   str                  A string in full TIMESTAMP format or
 
452
                        [-] DAYS [H]H:MM:SS, [H]H:MM:SS, [M]M:SS, [H]HMMSS,
 
453
                        [M]MSS or [S]S
 
454
                        There may be an optional [.second_part] after seconds
 
455
   length               Length of str
 
456
   l_time               Store result here
 
457
   warning              Set DRIZZLE_TIME_WARN_TRUNCATED flag if the input string
 
458
                        was cut during conversion, and/or
 
459
                        DRIZZLE_TIME_WARN_OUT_OF_RANGE flag, if the value is
 
460
                        out of range.
 
461
 
 
462
   NOTES
 
463
     Because of the extra days argument, this function can only
 
464
     work with times where the time arguments are in the above order.
 
465
 
 
466
   RETURN
 
467
     0  ok
 
468
     1  error
 
469
*/
 
470
 
 
471
bool str_to_time(const char *str, uint32_t length, DRIZZLE_TIME *l_time,
 
472
                    int *warning)
 
473
{
 
474
  uint32_t date[5];
 
475
  uint64_t value;
 
476
  const char *end=str+length, *end_of_days;
 
477
  bool found_days,found_hours;
 
478
  uint32_t state;
 
479
 
 
480
  l_time->neg=0;
 
481
  *warning= 0;
 
482
  for (; str != end && my_isspace(&my_charset_utf8_general_ci,*str) ; str++)
 
483
    length--;
 
484
  if (str != end && *str == '-')
 
485
  {
 
486
    l_time->neg=1;
 
487
    str++;
 
488
    length--;
 
489
  }
 
490
  if (str == end)
 
491
    return 1;
 
492
 
 
493
  /* Check first if this is a full TIMESTAMP */
 
494
  if (length >= 12)
 
495
  {                                             /* Probably full timestamp */
 
496
    int was_cut;
 
497
    enum enum_drizzle_timestamp_type
 
498
      res= str_to_datetime(str, length, l_time,
 
499
                           (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), &was_cut);
 
500
    if ((int) res >= (int) DRIZZLE_TIMESTAMP_ERROR)
 
501
    {
 
502
      if (was_cut)
 
503
        *warning|= DRIZZLE_TIME_WARN_TRUNCATED;
 
504
      return res == DRIZZLE_TIMESTAMP_ERROR;
 
505
    }
 
506
  }
 
507
 
 
508
  /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */
 
509
  for (value=0; str != end && my_isdigit(&my_charset_utf8_general_ci,*str) ; str++)
 
510
    value=value*10L + (long) (*str - '0');
 
511
 
 
512
  /* Skip all space after 'days' */
 
513
  end_of_days= str;
 
514
  for (; str != end && my_isspace(&my_charset_utf8_general_ci, str[0]) ; str++)
 
515
    ;
 
516
 
 
517
  found_days=found_hours=0;
 
518
  if ((uint) (end-str) > 1 && str != end_of_days &&
 
519
      my_isdigit(&my_charset_utf8_general_ci, *str))
 
520
  {                                             /* Found days part */
 
521
    date[0]= (uint32_t) value;
 
522
    state= 1;                                   /* Assume next is hours */
 
523
    found_days= 1;
 
524
  }
 
525
  else if ((end-str) > 1 &&  *str == time_separator &&
 
526
           my_isdigit(&my_charset_utf8_general_ci, str[1]))
 
527
  {
 
528
    date[0]= 0;                                 /* Assume we found hours */
 
529
    date[1]= (uint32_t) value;
 
530
    state=2;
 
531
    found_hours=1;
 
532
    str++;                                      /* skip ':' */
 
533
  }
 
534
  else
 
535
  {
 
536
    /* String given as one number; assume HHMMSS format */
 
537
    date[0]= 0;
 
538
    date[1]= (uint32_t) (value/10000);
 
539
    date[2]= (uint32_t) (value/100 % 100);
 
540
    date[3]= (uint32_t) (value % 100);
 
541
    state=4;
 
542
    goto fractional;
 
543
  }
 
544
 
 
545
  /* Read hours, minutes and seconds */
 
546
  for (;;)
 
547
  {
 
548
    for (value=0; str != end && my_isdigit(&my_charset_utf8_general_ci,*str) ; str++)
 
549
      value=value*10L + (long) (*str - '0');
 
550
    date[state++]= (uint32_t) value;
 
551
    if (state == 4 || (end-str) < 2 || *str != time_separator ||
 
552
        !my_isdigit(&my_charset_utf8_general_ci,str[1]))
 
553
      break;
 
554
    str++;                                      /* Skip time_separator (':') */
 
555
  }
 
556
 
 
557
  if (state != 4)
 
558
  {                                             /* Not HH:MM:SS */
 
559
    /* Fix the date to assume that seconds was given */
 
560
    if (!found_hours && !found_days)
 
561
    {
 
562
      bmove_upp((unsigned char*) (date+4), (unsigned char*) (date+state),
 
563
                sizeof(long)*(state-1));
 
564
      memset(date, 0, sizeof(long)*(4-state));
 
565
    }
 
566
    else
 
567
      memset(date+state, 0, sizeof(long)*(4-state));
 
568
  }
 
569
 
 
570
fractional:
 
571
  /* Get fractional second part */
 
572
  if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_utf8_general_ci,str[1]))
 
573
  {
 
574
    int field_length= 5;
 
575
    str++; value=(uint) (unsigned char) (*str - '0');
 
576
    while (++str != end && my_isdigit(&my_charset_utf8_general_ci, *str))
 
577
    {
 
578
      if (field_length-- > 0)
 
579
        value= value*10 + (uint) (unsigned char) (*str - '0');
 
580
    }
 
581
    if (field_length > 0)
 
582
      value*= (long) log_10_int[field_length];
 
583
    else if (field_length < 0)
 
584
      *warning|= DRIZZLE_TIME_WARN_TRUNCATED;
 
585
    date[4]= (uint32_t) value;
 
586
  }
 
587
  else
 
588
    date[4]=0;
 
589
    
 
590
  /* Check for exponent part: E<gigit> | E<sign><digit> */
 
591
  /* (may occur as result of %g formatting of time value) */
 
592
  if ((end - str) > 1 &&
 
593
      (*str == 'e' || *str == 'E') &&
 
594
      (my_isdigit(&my_charset_utf8_general_ci, str[1]) ||
 
595
       ((str[1] == '-' || str[1] == '+') &&
 
596
        (end - str) > 2 &&
 
597
        my_isdigit(&my_charset_utf8_general_ci, str[2]))))
 
598
    return 1;
 
599
 
 
600
  if (internal_format_positions[7] != 255)
 
601
  {
 
602
    /* Read a possible AM/PM */
 
603
    while (str != end && my_isspace(&my_charset_utf8_general_ci, *str))
 
604
      str++;
 
605
    if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
 
606
    {
 
607
      if (str[0] == 'p' || str[0] == 'P')
 
608
      {
 
609
        str+= 2;
 
610
        date[1]= date[1]%12 + 12;
 
611
      }
 
612
      else if (str[0] == 'a' || str[0] == 'A')
 
613
        str+=2;
 
614
    }
 
615
  }
 
616
 
 
617
  /* Integer overflow checks */
 
618
  if (date[0] > UINT_MAX || date[1] > UINT_MAX ||
 
619
      date[2] > UINT_MAX || date[3] > UINT_MAX ||
 
620
      date[4] > UINT_MAX)
 
621
    return 1;
 
622
  
 
623
  l_time->year=         0;                      /* For protocol::store_time */
 
624
  l_time->month=        0;
 
625
  l_time->day=          date[0];
 
626
  l_time->hour=         date[1];
 
627
  l_time->minute=       date[2];
 
628
  l_time->second=       date[3];
 
629
  l_time->second_part=  date[4];
 
630
  l_time->time_type= DRIZZLE_TIMESTAMP_TIME;
 
631
 
 
632
  /* Check if the value is valid and fits into DRIZZLE_TIME range */
 
633
  if (check_time_range(l_time, warning))
 
634
    return 1;
 
635
  
 
636
  /* Check if there is garbage at end of the DRIZZLE_TIME specification */
 
637
  if (str != end)
 
638
  {
 
639
    do
 
640
    {
 
641
      if (!my_isspace(&my_charset_utf8_general_ci,*str))
 
642
      {
 
643
        *warning|= DRIZZLE_TIME_WARN_TRUNCATED;
 
644
        break;
 
645
      }
 
646
    } while (++str != end);
 
647
  }
 
648
  return 0;
 
649
}
 
650
 
 
651
 
 
652
/*
 
653
  Check 'time' value to lie in the DRIZZLE_TIME range
 
654
 
 
655
  SYNOPSIS:
 
656
    check_time_range()
 
657
    time     pointer to DRIZZLE_TIME value
 
658
    warning  set DRIZZLE_TIME_WARN_OUT_OF_RANGE flag if the value is out of range
 
659
 
 
660
  DESCRIPTION
 
661
  If the time value lies outside of the range [-838:59:59, 838:59:59],
 
662
  set it to the closest endpoint of the range and set
 
663
  DRIZZLE_TIME_WARN_OUT_OF_RANGE flag in the 'warning' variable.
 
664
 
 
665
  RETURN
 
666
    0        time value is valid, but was possibly truncated
 
667
    1        time value is invalid
 
668
*/
 
669
 
 
670
int check_time_range(DRIZZLE_TIME *my_time, int *warning) 
 
671
{
 
672
  int64_t hour;
 
673
 
 
674
  if (my_time->minute >= 60 || my_time->second >= 60)
 
675
    return 1;
 
676
 
 
677
  hour= my_time->hour + (24*my_time->day);
 
678
  if (hour <= TIME_MAX_HOUR &&
 
679
      (hour != TIME_MAX_HOUR || my_time->minute != TIME_MAX_MINUTE ||
 
680
       my_time->second != TIME_MAX_SECOND || !my_time->second_part))
 
681
    return 0;
 
682
 
 
683
  my_time->day= 0;
 
684
  my_time->hour= TIME_MAX_HOUR;
 
685
  my_time->minute= TIME_MAX_MINUTE;
 
686
  my_time->second= TIME_MAX_SECOND;
 
687
  my_time->second_part= 0;
 
688
  *warning|= DRIZZLE_TIME_WARN_OUT_OF_RANGE;
 
689
  return 0;
 
690
}
 
691
 
 
692
 
 
693
/*
 
694
  Prepare offset of system time zone from UTC for my_system_gmt_sec() func.
 
695
 
 
696
  SYNOPSIS
 
697
    init_time()
 
698
*/
 
699
void init_time(void)
 
700
{
 
701
  time_t seconds;
 
702
  struct tm *l_time,tm_tmp;
 
703
  DRIZZLE_TIME my_time;
 
704
  bool not_used;
 
705
 
 
706
  seconds= (time_t) time((time_t*) 0);
 
707
  localtime_r(&seconds,&tm_tmp);
 
708
  l_time= &tm_tmp;
 
709
  my_time_zone=         3600;           /* Comp. for -3600 in my_gmt_sec */
 
710
  my_time.year=         (uint) l_time->tm_year+1900;
 
711
  my_time.month=        (uint) l_time->tm_mon+1;
 
712
  my_time.day=          (uint) l_time->tm_mday;
 
713
  my_time.hour=         (uint) l_time->tm_hour;
 
714
  my_time.minute=       (uint) l_time->tm_min;
 
715
  my_time.second=       (uint) l_time->tm_sec;
 
716
  my_system_gmt_sec(&my_time, &my_time_zone, &not_used); /* Init my_time_zone */
 
717
}
 
718
 
 
719
 
 
720
/*
 
721
  Handle 2 digit year conversions
 
722
 
 
723
  SYNOPSIS
 
724
  year_2000_handling()
 
725
  year     2 digit year
 
726
 
 
727
  RETURN
 
728
    Year between 1970-2069
 
729
*/
 
730
 
 
731
uint32_t year_2000_handling(uint32_t year)
 
732
{
 
733
  if ((year=year+1900) < 1900+YY_PART_YEAR)
 
734
    year+=100;
 
735
  return year;
 
736
}
 
737
 
 
738
 
 
739
/*
 
740
  Calculate nr of day since year 0 in new date-system (from 1615)
 
741
 
 
742
  SYNOPSIS
 
743
    calc_daynr()
 
744
    year                 Year (exact 4 digit year, no year conversions)
 
745
    month                Month
 
746
    day                  Day
 
747
 
 
748
  NOTES: 0000-00-00 is a valid date, and will return 0
 
749
 
 
750
  RETURN
 
751
    Days since 0000-00-00
 
752
*/
 
753
 
 
754
long calc_daynr(uint32_t year,uint32_t month,uint32_t day)
 
755
{
 
756
  long delsum;
 
757
  int temp;
 
758
 
 
759
  if (year == 0 && month == 0 && day == 0)
 
760
    return(0);                          /* Skip errors */
 
761
  delsum= (long) (365L * year+ 31*(month-1) +day);
 
762
  if (month <= 2)
 
763
      year--;
 
764
  else
 
765
    delsum-= (long) (month*4+23)/10;
 
766
  temp=(int) ((year/100+1)*3)/4;
 
767
  return(delsum+(int) year/4-temp);
 
768
} /* calc_daynr */
 
769
 
 
770
 
 
771
/*
 
772
  Convert time in DRIZZLE_TIME representation in system time zone to its
 
773
  my_time_t form (number of seconds in UTC since begginning of Unix Epoch).
 
774
 
 
775
  SYNOPSIS
 
776
    my_system_gmt_sec()
 
777
      t               - time value to be converted
 
778
      my_timezone     - pointer to long where offset of system time zone
 
779
                        from UTC will be stored for caching
 
780
      in_dst_time_gap - set to true if time falls into spring time-gap
 
781
 
 
782
  NOTES
 
783
    The idea is to cache the time zone offset from UTC (including daylight 
 
784
    saving time) for the next call to make things faster. But currently we 
 
785
    just calculate this offset during startup (by calling init_time() 
 
786
    function) and use it all the time.
 
787
    Time value provided should be legal time value (e.g. '2003-01-01 25:00:00'
 
788
    is not allowed).
 
789
 
 
790
  RETURN VALUE
 
791
    Time in UTC seconds since Unix Epoch representation.
 
792
*/
 
793
my_time_t
 
794
my_system_gmt_sec(const DRIZZLE_TIME *t_src, long *my_timezone,
 
795
                  bool *in_dst_time_gap)
 
796
{
 
797
  uint32_t loop;
 
798
  time_t tmp= 0;
 
799
  int shift= 0;
 
800
  DRIZZLE_TIME tmp_time;
 
801
  DRIZZLE_TIME *t= &tmp_time;
 
802
  struct tm *l_time,tm_tmp;
 
803
  long diff, current_timezone;
 
804
 
 
805
  /*
 
806
    Use temp variable to avoid trashing input data, which could happen in
 
807
    case of shift required for boundary dates processing.
 
808
  */
 
809
  memcpy(&tmp_time, t_src, sizeof(DRIZZLE_TIME));
 
810
 
 
811
  if (!validate_timestamp_range(t))
 
812
    return 0;
 
813
 
 
814
  /*
 
815
    Calculate the gmt time based on current time and timezone
 
816
    The -1 on the end is to ensure that if have a date that exists twice
 
817
    (like 2002-10-27 02:00:0 MET), we will find the initial date.
 
818
 
 
819
    By doing -3600 we will have to call localtime_r() several times, but
 
820
    I couldn't come up with a better way to get a repeatable result :(
 
821
 
 
822
    We can't use mktime() as it's buggy on many platforms and not thread safe.
 
823
 
 
824
    Note: this code assumes that our time_t estimation is not too far away
 
825
    from real value (we assume that localtime_r(tmp) will return something
 
826
    within 24 hrs from t) which is probably true for all current time zones.
 
827
 
 
828
    Note2: For the dates, which have time_t representation close to
 
829
    MAX_INT32 (efficient time_t limit for supported platforms), we should
 
830
    do a small trick to avoid overflow. That is, convert the date, which is
 
831
    two days earlier, and then add these days to the final value.
 
832
 
 
833
    The same trick is done for the values close to 0 in time_t
 
834
    representation for platfroms with unsigned time_t (QNX).
 
835
 
 
836
    To be more verbose, here is a sample (extracted from the code below):
 
837
    (calc_daynr(2038, 1, 19) - (long) days_at_timestart)*86400L + 4*3600L
 
838
    would return -2147480896 because of the long type overflow. In result
 
839
    we would get 1901 year in localtime_r(), which is an obvious error.
 
840
 
 
841
    Alike problem raises with the dates close to Epoch. E.g.
 
842
    (calc_daynr(1969, 12, 31) - (long) days_at_timestart)*86400L + 23*3600L
 
843
    will give -3600.
 
844
 
 
845
    On some platforms, (E.g. on QNX) time_t is unsigned and localtime(-3600)
 
846
    wil give us a date around 2106 year. Which is no good.
 
847
 
 
848
    Theoreticaly, there could be problems with the latter conversion:
 
849
    there are at least two timezones, which had time switches near 1 Jan
 
850
    of 1970 (because of political reasons). These are America/Hermosillo and
 
851
    America/Mazatlan time zones. They changed their offset on
 
852
    1970-01-01 08:00:00 UTC from UTC-8 to UTC-7. For these zones
 
853
    the code below will give incorrect results for dates close to
 
854
    1970-01-01, in the case OS takes into account these historical switches.
 
855
    Luckily, it seems that we support only one platform with unsigned
 
856
    time_t. It's QNX. And QNX does not support historical timezone data at all.
 
857
    E.g. there are no /usr/share/zoneinfo/ files or any other mean to supply
 
858
    historical information for localtime_r() etc. That is, the problem is not
 
859
    relevant to QNX.
 
860
 
 
861
    We are safe with shifts close to MAX_INT32, as there are no known
 
862
    time switches on Jan 2038 yet :)
 
863
  */
 
864
  if ((t->year == TIMESTAMP_MAX_YEAR) && (t->month == 1) && (t->day > 4))
 
865
  {
 
866
    /*
 
867
      Below we will pass (uint) (t->day - shift) to calc_daynr.
 
868
      As we don't want to get an overflow here, we will shift
 
869
      only safe dates. That's why we have (t->day > 4) above.
 
870
    */
 
871
    t->day-= 2;
 
872
    shift= 2;
 
873
  }
 
874
#ifdef TIME_T_UNSIGNED
 
875
  else
 
876
  {
 
877
    /*
 
878
      We can get 0 in time_t representaion only on 1969, 31 of Dec or on
 
879
      1970, 1 of Jan. For both dates we use shift, which is added
 
880
      to t->day in order to step out a bit from the border.
 
881
      This is required for platforms, where time_t is unsigned.
 
882
      As far as I know, among the platforms we support it's only QNX.
 
883
      Note: the order of below if-statements is significant.
 
884
    */
 
885
 
 
886
    if ((t->year == TIMESTAMP_MIN_YEAR + 1) && (t->month == 1)
 
887
        && (t->day <= 10))
 
888
    {
 
889
      t->day+= 2;
 
890
      shift= -2;
 
891
    }
 
892
 
 
893
    if ((t->year == TIMESTAMP_MIN_YEAR) && (t->month == 12)
 
894
        && (t->day == 31))
 
895
    {
 
896
      t->year++;
 
897
      t->month= 1;
 
898
      t->day= 2;
 
899
      shift= -2;
 
900
    }
 
901
  }
 
902
#endif
 
903
 
 
904
  tmp= (time_t) (((calc_daynr((uint) t->year, (uint) t->month, (uint) t->day) -
 
905
                   (long) days_at_timestart)*86400L + (long) t->hour*3600L +
 
906
                  (long) (t->minute*60 + t->second)) + (time_t) my_time_zone -
 
907
                 3600);
 
908
 
 
909
  current_timezone= my_time_zone;
 
910
  localtime_r(&tmp,&tm_tmp);
 
911
  l_time=&tm_tmp;
 
912
  for (loop=0;
 
913
       loop < 2 &&
 
914
         (t->hour != (uint) l_time->tm_hour ||
 
915
          t->minute != (uint) l_time->tm_min ||
 
916
          t->second != (uint) l_time->tm_sec);
 
917
       loop++)
 
918
  {                                     /* One check should be enough ? */
 
919
    /* Get difference in days */
 
920
    int days= t->day - l_time->tm_mday;
 
921
    if (days < -1)
 
922
      days= 1;                                  /* Month has wrapped */
 
923
    else if (days > 1)
 
924
      days= -1;
 
925
    diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour)) +
 
926
          (long) (60*((int) t->minute - (int) l_time->tm_min)) +
 
927
          (long) ((int) t->second - (int) l_time->tm_sec));
 
928
    current_timezone+= diff+3600;               /* Compensate for -3600 above */
 
929
    tmp+= (time_t) diff;
 
930
    localtime_r(&tmp,&tm_tmp);
 
931
    l_time=&tm_tmp;
 
932
  }
 
933
  /*
 
934
    Fix that if we are in the non existing daylight saving time hour
 
935
    we move the start of the next real hour.
 
936
 
 
937
    This code doesn't handle such exotical thing as time-gaps whose length
 
938
    is more than one hour or non-integer (latter can theoretically happen
 
939
    if one of seconds will be removed due leap correction, or because of
 
940
    general time correction like it happened for Africa/Monrovia time zone
 
941
    in year 1972).
 
942
  */
 
943
  if (loop == 2 && t->hour != (uint) l_time->tm_hour)
 
944
  {
 
945
    int days= t->day - l_time->tm_mday;
 
946
    if (days < -1)
 
947
      days=1;                                   /* Month has wrapped */
 
948
    else if (days > 1)
 
949
      days= -1;
 
950
    diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour))+
 
951
          (long) (60*((int) t->minute - (int) l_time->tm_min)) +
 
952
          (long) ((int) t->second - (int) l_time->tm_sec));
 
953
    if (diff == 3600)
 
954
      tmp+=3600 - t->minute*60 - t->second;     /* Move to next hour */
 
955
    else if (diff == -3600)
 
956
      tmp-=t->minute*60 + t->second;            /* Move to previous hour */
 
957
 
 
958
    *in_dst_time_gap= true;
 
959
  }
 
960
  *my_timezone= current_timezone;
 
961
 
 
962
 
 
963
  /* shift back, if we were dealing with boundary dates */
 
964
  tmp+= shift*86400L;
 
965
 
 
966
  /*
 
967
    This is possible for dates, which slightly exceed boundaries.
 
968
    Conversion will pass ok for them, but we don't allow them.
 
969
    First check will pass for platforms with signed time_t.
 
970
    instruction above (tmp+= shift*86400L) could exceed
 
971
    MAX_INT32 (== TIMESTAMP_MAX_VALUE) and overflow will happen.
 
972
    So, tmp < TIMESTAMP_MIN_VALUE will be triggered. On platfroms
 
973
    with unsigned time_t tmp+= shift*86400L might result in a number,
 
974
    larger then TIMESTAMP_MAX_VALUE, so another check will work.
 
975
  */
 
976
  if ((tmp < TIMESTAMP_MIN_VALUE) || (tmp > TIMESTAMP_MAX_VALUE))
 
977
    tmp= 0;
 
978
 
 
979
  return (my_time_t) tmp;
 
980
} /* my_system_gmt_sec */
 
981
 
 
982
 
 
983
/* Set DRIZZLE_TIME structure to 0000-00-00 00:00:00.000000 */
 
984
 
 
985
void set_zero_time(DRIZZLE_TIME *tm, enum enum_drizzle_timestamp_type time_type)
 
986
{
 
987
  memset(tm, 0, sizeof(*tm));
 
988
  tm->time_type= time_type;
 
989
}
 
990
 
 
991
 
 
992
/*
 
993
  Functions to convert time/date/datetime value to a string,
 
994
  using default format.
 
995
  This functions don't check that given DRIZZLE_TIME structure members are
 
996
  in valid range. If they are not, return value won't reflect any
 
997
  valid date either. Additionally, make_time doesn't take into
 
998
  account time->day member: it's assumed that days have been converted
 
999
  to hours already.
 
1000
 
 
1001
  RETURN
 
1002
    number of characters written to 'to'
 
1003
*/
 
1004
 
 
1005
int my_time_to_str(const DRIZZLE_TIME *l_time, char *to)
 
1006
{
 
1007
  uint32_t extra_hours= 0;
 
1008
  return sprintf(to, "%s%02u:%02u:%02u",
 
1009
                         (l_time->neg ? "-" : ""),
 
1010
                         extra_hours+ l_time->hour,
 
1011
                         l_time->minute,
 
1012
                         l_time->second);
 
1013
}
 
1014
 
 
1015
int my_date_to_str(const DRIZZLE_TIME *l_time, char *to)
 
1016
{
 
1017
  return sprintf(to, "%04u-%02u-%02u",
 
1018
                         l_time->year,
 
1019
                         l_time->month,
 
1020
                         l_time->day);
 
1021
}
 
1022
 
 
1023
int my_datetime_to_str(const DRIZZLE_TIME *l_time, char *to)
 
1024
{
 
1025
  return sprintf(to, "%04u-%02u-%02u %02u:%02u:%02u",
 
1026
                         l_time->year,
 
1027
                         l_time->month,
 
1028
                         l_time->day,
 
1029
                         l_time->hour,
 
1030
                         l_time->minute,
 
1031
                         l_time->second);
 
1032
}
 
1033
 
 
1034
 
 
1035
/*
 
1036
  Convert struct DATE/TIME/DATETIME value to string using built-in
 
1037
  MySQL time conversion formats.
 
1038
 
 
1039
  SYNOPSIS
 
1040
    my_TIME_to_string()
 
1041
 
 
1042
  NOTE
 
1043
    The string must have at least MAX_DATE_STRING_REP_LENGTH bytes reserved.
 
1044
*/
 
1045
 
 
1046
int my_TIME_to_str(const DRIZZLE_TIME *l_time, char *to)
 
1047
{
 
1048
  switch (l_time->time_type) {
 
1049
  case DRIZZLE_TIMESTAMP_DATETIME:
 
1050
    return my_datetime_to_str(l_time, to);
 
1051
  case DRIZZLE_TIMESTAMP_DATE:
 
1052
    return my_date_to_str(l_time, to);
 
1053
  case DRIZZLE_TIMESTAMP_TIME:
 
1054
    return my_time_to_str(l_time, to);
 
1055
  case DRIZZLE_TIMESTAMP_NONE:
 
1056
  case DRIZZLE_TIMESTAMP_ERROR:
 
1057
    to[0]='\0';
 
1058
    return 0;
 
1059
  default:
 
1060
    assert(0);
 
1061
    return 0;
 
1062
  }
 
1063
}
 
1064
 
 
1065
 
 
1066
/*
 
1067
  Convert datetime value specified as number to broken-down TIME
 
1068
  representation and form value of DATETIME type as side-effect.
 
1069
 
 
1070
  SYNOPSIS
 
1071
    number_to_datetime()
 
1072
      nr         - datetime value as number
 
1073
      time_res   - pointer for structure for broken-down representation
 
1074
      flags      - flags to use in validating date, as in str_to_datetime()
 
1075
      was_cut    0      Value ok
 
1076
                 1      If value was cut during conversion
 
1077
                 2      check_date(date,flags) considers date invalid
 
1078
 
 
1079
  DESCRIPTION
 
1080
    Convert a datetime value of formats YYMMDD, YYYYMMDD, YYMMDDHHMSS,
 
1081
    YYYYMMDDHHMMSS to broken-down DRIZZLE_TIME representation. Return value in
 
1082
    YYYYMMDDHHMMSS format as side-effect.
 
1083
 
 
1084
    This function also checks if datetime value fits in DATETIME range.
 
1085
 
 
1086
  RETURN VALUE
 
1087
    -1              Timestamp with wrong values
 
1088
    anything else   DATETIME as integer in YYYYMMDDHHMMSS format
 
1089
    Datetime value in YYYYMMDDHHMMSS format.
 
1090
*/
 
1091
 
 
1092
int64_t number_to_datetime(int64_t nr, DRIZZLE_TIME *time_res,
 
1093
                            uint32_t flags, int *was_cut)
 
1094
{
 
1095
  long part1,part2;
 
1096
 
 
1097
  *was_cut= 0;
 
1098
  memset(time_res, 0, sizeof(*time_res));
 
1099
  time_res->time_type=DRIZZLE_TIMESTAMP_DATE;
 
1100
 
 
1101
  if (nr == 0LL || nr >= 10000101000000LL)
 
1102
  {
 
1103
    time_res->time_type=DRIZZLE_TIMESTAMP_DATETIME;
 
1104
    goto ok;
 
1105
  }
 
1106
  if (nr < 101)
 
1107
    goto err;
 
1108
  if (nr <= (YY_PART_YEAR-1)*10000L+1231L)
 
1109
  {
 
1110
    nr= (nr+20000000L)*1000000L;                 /* YYMMDD, year: 2000-2069 */
 
1111
    goto ok;
 
1112
  }
 
1113
  if (nr < (YY_PART_YEAR)*10000L+101L)
 
1114
    goto err;
 
1115
  if (nr <= 991231L)
 
1116
  {
 
1117
    nr= (nr+19000000L)*1000000L;                 /* YYMMDD, year: 1970-1999 */
 
1118
    goto ok;
 
1119
  }
 
1120
  if (nr < 10000101L)
 
1121
    goto err;
 
1122
  if (nr <= 99991231L)
 
1123
  {
 
1124
    nr= nr*1000000L;
 
1125
    goto ok;
 
1126
  }
 
1127
  if (nr < 101000000L)
 
1128
    goto err;
 
1129
 
 
1130
  time_res->time_type=DRIZZLE_TIMESTAMP_DATETIME;
 
1131
 
 
1132
  if (nr <= (YY_PART_YEAR-1) * 10000000000LL + 1231235959LL)
 
1133
  {
 
1134
    nr= nr + 20000000000000LL;                   /* YYMMDDHHMMSS, 2000-2069 */
 
1135
    goto ok;
 
1136
  }
 
1137
  if (nr <  YY_PART_YEAR * 10000000000LL + 101000000LL)
 
1138
    goto err;
 
1139
  if (nr <= 991231235959LL)
 
1140
    nr= nr + 19000000000000LL;          /* YYMMDDHHMMSS, 1970-1999 */
 
1141
 
 
1142
 ok:
 
1143
  part1=(long) (nr / 1000000LL);
 
1144
  part2=(long) (nr - (int64_t) part1 * 1000000LL);
 
1145
  time_res->year=  (int) (part1/10000L);  part1%=10000L;
 
1146
  time_res->month= (int) part1 / 100;
 
1147
  time_res->day=   (int) part1 % 100;
 
1148
  time_res->hour=  (int) (part2/10000L);  part2%=10000L;
 
1149
  time_res->minute=(int) part2 / 100;
 
1150
  time_res->second=(int) part2 % 100;
 
1151
 
 
1152
  if (time_res->year <= 9999 && time_res->month <= 12 &&
 
1153
      time_res->day <= 31 && time_res->hour <= 23 &&
 
1154
      time_res->minute <= 59 && time_res->second <= 59 &&
 
1155
      !check_date(time_res, (nr != 0), flags, was_cut))
 
1156
    return nr;
 
1157
 
 
1158
  /* Don't want to have was_cut get set if NO_ZERO_DATE was violated. */
 
1159
  if (!nr && (flags & TIME_NO_ZERO_DATE))
 
1160
    return -1LL;
 
1161
 
 
1162
 err:
 
1163
  *was_cut= 1;
 
1164
  return -1LL;
 
1165
}
 
1166
 
 
1167
 
 
1168
/* Convert time value to integer in YYYYMMDDHHMMSS format */
 
1169
 
 
1170
uint64_t TIME_to_uint64_t_datetime(const DRIZZLE_TIME *my_time)
 
1171
{
 
1172
  return ((uint64_t) (my_time->year * 10000UL +
 
1173
                       my_time->month * 100UL +
 
1174
                       my_time->day) * 1000000ULL +
 
1175
          (uint64_t) (my_time->hour * 10000UL +
 
1176
                       my_time->minute * 100UL +
 
1177
                       my_time->second));
 
1178
}
 
1179
 
 
1180
 
 
1181
/* Convert DRIZZLE_TIME value to integer in YYYYMMDD format */
 
1182
 
 
1183
uint64_t TIME_to_uint64_t_date(const DRIZZLE_TIME *my_time)
 
1184
{
 
1185
  return (uint64_t) (my_time->year * 10000UL + my_time->month * 100UL +
 
1186
                      my_time->day);
 
1187
}
 
1188
 
 
1189
 
 
1190
/*
 
1191
  Convert DRIZZLE_TIME value to integer in HHMMSS format.
 
1192
  This function doesn't take into account time->day member:
 
1193
  it's assumed that days have been converted to hours already.
 
1194
*/
 
1195
 
 
1196
uint64_t TIME_to_uint64_t_time(const DRIZZLE_TIME *my_time)
 
1197
{
 
1198
  return (uint64_t) (my_time->hour * 10000UL +
 
1199
                      my_time->minute * 100UL +
 
1200
                      my_time->second);
 
1201
}
 
1202
 
 
1203
 
 
1204
/*
 
1205
  Convert struct DRIZZLE_TIME (date and time split into year/month/day/hour/...
 
1206
  to a number in format YYYYMMDDHHMMSS (DATETIME),
 
1207
  YYYYMMDD (DATE)  or HHMMSS (TIME).
 
1208
 
 
1209
  SYNOPSIS
 
1210
    TIME_to_uint64_t()
 
1211
 
 
1212
  DESCRIPTION
 
1213
    The function is used when we need to convert value of time item
 
1214
    to a number if it's used in numeric context, i. e.:
 
1215
    SELECT NOW()+1, CURDATE()+0, CURTIMIE()+0;
 
1216
    SELECT ?+1;
 
1217
 
 
1218
  NOTE
 
1219
    This function doesn't check that given DRIZZLE_TIME structure members are
 
1220
    in valid range. If they are not, return value won't reflect any
 
1221
    valid date either.
 
1222
*/
 
1223
 
 
1224
uint64_t TIME_to_uint64_t(const DRIZZLE_TIME *my_time)
 
1225
{
 
1226
  switch (my_time->time_type) {
 
1227
  case DRIZZLE_TIMESTAMP_DATETIME:
 
1228
    return TIME_to_uint64_t_datetime(my_time);
 
1229
  case DRIZZLE_TIMESTAMP_DATE:
 
1230
    return TIME_to_uint64_t_date(my_time);
 
1231
  case DRIZZLE_TIMESTAMP_TIME:
 
1232
    return TIME_to_uint64_t_time(my_time);
 
1233
  case DRIZZLE_TIMESTAMP_NONE:
 
1234
  case DRIZZLE_TIMESTAMP_ERROR:
 
1235
    return 0ULL;
 
1236
  default:
 
1237
    assert(0);
 
1238
  }
 
1239
  return 0;
 
1240
}
 
1241