~drizzle-trunk/drizzle/development

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