~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/time_functions.cc

  • Committer: Stewart Smith
  • Date: 2010-02-15 03:55:09 UTC
  • mto: (1273.13.96 build)
  • mto: This revision was merged to the branch mainline in revision 1308.
  • Revision ID: stewart@flamingspork.com-20100215035509-y6sry4q4yymph2by
move SUBSTR, SUBSTRING and SUBSTR_INDEX to plugins. add parser hooks for substr being a plugin now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-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 */
 
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008-2009 Sun Microsystems
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
15
19
 
16
20
 
17
21
/* Functions to handle date and time */
18
22
 
19
 
#include <drizzled/server_includes.h>
20
 
#include <drizzled/drizzled_error_messages.h>
21
 
 
22
 
 
23
 
        /* Some functions to calculate dates */
24
 
 
25
 
#ifndef TESTTIME
26
 
 
27
 
/*
28
 
  Name description of interval names used in statements.
29
 
 
30
 
  'interval_type_to_name' is ordered and sorted on interval size and
31
 
  interval complexity.
32
 
  Order of elements in 'interval_type_to_name' should correspond to 
33
 
  the order of elements in 'interval_type' enum
34
 
  
35
 
  See also interval_type, interval_names
36
 
*/
37
 
 
38
 
LEX_STRING interval_type_to_name[INTERVAL_LAST] = {
39
 
  { C_STRING_WITH_LEN("YEAR")},
40
 
  { C_STRING_WITH_LEN("QUARTER")},
41
 
  { C_STRING_WITH_LEN("MONTH")},
42
 
  { C_STRING_WITH_LEN("WEEK")},
43
 
  { C_STRING_WITH_LEN("DAY")},
44
 
  { C_STRING_WITH_LEN("HOUR")},
45
 
  { C_STRING_WITH_LEN("MINUTE")},
46
 
  { C_STRING_WITH_LEN("SECOND")},
47
 
  { C_STRING_WITH_LEN("MICROSECOND")},
48
 
  { C_STRING_WITH_LEN("YEAR_MONTH")},
49
 
  { C_STRING_WITH_LEN("DAY_HOUR")},
50
 
  { C_STRING_WITH_LEN("DAY_MINUTE")},
51
 
  { C_STRING_WITH_LEN("DAY_SECOND")},
52
 
  { C_STRING_WITH_LEN("HOUR_MINUTE")},
53
 
  { C_STRING_WITH_LEN("HOUR_SECOND")},
54
 
  { C_STRING_WITH_LEN("MINUTE_SECOND")},
55
 
  { C_STRING_WITH_LEN("DAY_MICROSECOND")},
56
 
  { C_STRING_WITH_LEN("HOUR_MICROSECOND")},
57
 
  { C_STRING_WITH_LEN("MINUTE_MICROSECOND")},
58
 
  { C_STRING_WITH_LEN("SECOND_MICROSECOND")}
59
 
}; 
60
 
 
61
 
        /* Calc weekday from daynr */
62
 
        /* Returns 0 for monday, 1 for tuesday .... */
 
23
#include "config.h"
 
24
#include "drizzled/error.h"
 
25
#include "drizzled/util/test.h"
 
26
#include "drizzled/tztime.h"
 
27
#include "drizzled/session.h"
 
28
#include "drizzled/time_functions.h"
 
29
 
 
30
namespace drizzled
 
31
{
 
32
 
 
33
/* Some functions to calculate dates */
 
34
 
63
35
 
64
36
int calc_weekday(long daynr,bool sunday_first_day_of_week)
65
37
{
66
38
  return ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
67
39
}
68
40
 
69
 
/*
70
 
  The bits in week_format has the following meaning:
71
 
   WEEK_MONDAY_FIRST (0)  If not set    Sunday is first day of week
72
 
                          If set        Monday is first day of week
73
 
   WEEK_YEAR (1)          If not set    Week is in range 0-53
74
 
 
75
 
        Week 0 is returned for the the last week of the previous year (for
76
 
        a date at start of january) In this case one can get 53 for the
77
 
        first week of next year.  This flag ensures that the week is
78
 
        relevant for the given year. Note that this flag is only
79
 
        releveant if WEEK_JANUARY is not set.
80
 
 
81
 
                          If set         Week is in range 1-53.
82
 
 
83
 
        In this case one may get week 53 for a date in January (when
84
 
        the week is that last week of previous year) and week 1 for a
85
 
        date in December.
86
 
 
87
 
  WEEK_FIRST_WEEKDAY (2)  If not set    Weeks are numbered according
88
 
                                        to ISO 8601:1988
89
 
                          If set        The week that contains the first
90
 
                                        'first-day-of-week' is week 1.
91
 
        
92
 
        ISO 8601:1988 means that if the week containing January 1 has
93
 
        four or more days in the new year, then it is week 1;
94
 
        Otherwise it is the last week of the previous year, and the
95
 
        next week is week 1.
96
 
*/
97
 
 
98
 
uint calc_week(DRIZZLE_TIME *l_time, uint week_behaviour, uint *year)
 
41
 
 
42
uint32_t calc_week(DRIZZLE_TIME *l_time, uint32_t week_behaviour, uint32_t *year)
99
43
{
100
 
  uint days;
101
 
  ulong daynr=calc_daynr(l_time->year,l_time->month,l_time->day);
102
 
  ulong first_daynr=calc_daynr(l_time->year,1,1);
 
44
  uint32_t days;
 
45
  uint32_t daynr= calc_daynr(l_time->year,l_time->month,l_time->day);
 
46
  uint32_t first_daynr= calc_daynr(l_time->year,1,1);
103
47
  bool monday_first= test(week_behaviour & WEEK_MONDAY_FIRST);
104
48
  bool week_year= test(week_behaviour & WEEK_YEAR);
105
49
  bool first_weekday= test(week_behaviour & WEEK_FIRST_WEEKDAY);
106
50
 
107
 
  uint weekday=calc_weekday(first_daynr, !monday_first);
 
51
  uint32_t weekday= calc_weekday(first_daynr, !monday_first);
108
52
  *year=l_time->year;
109
53
 
110
54
  if (l_time->month == 1 && l_time->day <= 7-weekday)
135
79
  return days/7+1;
136
80
}
137
81
 
138
 
        /* Change a daynr to year, month and day */
139
 
        /* Daynr 0 is returned as date 00.00.00 */
140
82
 
141
 
void get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month,
142
 
                         uint *ret_day)
 
83
void get_date_from_daynr(long daynr,
 
84
                         uint32_t *ret_year,
 
85
                         uint32_t *ret_month,
 
86
                                           uint32_t *ret_day)
143
87
{
144
 
  uint year,temp,leap_day,day_of_year,days_in_year;
145
 
  uchar *month_pos;
 
88
  uint32_t year,temp,leap_day,day_of_year,days_in_year;
 
89
  unsigned char *month_pos;
146
90
 
147
91
  if (daynr <= 365L || daynr >= 3652500)
148
92
  {                                             /* Fix if wrong daynr */
150
94
  }
151
95
  else
152
96
  {
153
 
    year= (uint) (daynr*100 / 36525L);
 
97
    year= (uint32_t) (daynr*100 / 36525L);
154
98
    temp=(((year-1)/100+1)*3)/4;
155
 
    day_of_year=(uint) (daynr - (long) year * 365L) - (year-1)/4 +temp;
 
99
    day_of_year=(uint32_t) (daynr - (long) year * 365L) - (year-1)/4 +temp;
156
100
    while (day_of_year > (days_in_year= calc_days_in_year(year)))
157
101
    {
158
102
      day_of_year-=days_in_year;
170
114
    }
171
115
    *ret_month=1;
172
116
    for (month_pos= days_in_month ;
173
 
         day_of_year > (uint) *month_pos ;
 
117
         day_of_year > (uint32_t) *month_pos ;
174
118
         day_of_year-= *(month_pos++), (*ret_month)++)
175
119
      ;
176
120
    *ret_year=year;
179
123
  return;
180
124
}
181
125
 
182
 
        /* Functions to handle periods */
183
 
 
184
 
ulong convert_period_to_month(ulong period)
185
 
{
186
 
  ulong a,b;
187
 
  if (period == 0)
188
 
    return 0L;
189
 
  if ((a=period/100) < YY_PART_YEAR)
190
 
    a+=2000;
191
 
  else if (a < 100)
192
 
    a+=1900;
193
 
  b=period%100;
194
 
  return a*12+b-1;
195
 
}
196
 
 
197
 
 
198
 
ulong convert_month_to_period(ulong month)
199
 
{
200
 
  ulong year;
201
 
  if (month == 0L)
202
 
    return 0L;
203
 
  if ((year=month/12) < 100)
204
 
  {
205
 
    year+=(year < YY_PART_YEAR) ? 2000 : 1900;
206
 
  }
207
 
  return year*100+month%12+1;
208
 
}
209
 
 
210
 
 
211
 
/*
212
 
  Convert a timestamp string to a DRIZZLE_TIME value and produce a warning 
213
 
  if string was truncated during conversion.
214
 
 
215
 
  NOTE
216
 
    See description of str_to_datetime() for more information.
217
 
*/
218
 
 
219
 
timestamp_type
220
 
str_to_datetime_with_warn(const char *str, uint length, DRIZZLE_TIME *l_time,
221
 
                          uint flags)
 
126
 
 
127
enum enum_drizzle_timestamp_type
 
128
str_to_datetime_with_warn(const char *str, 
 
129
                          uint32_t length, 
 
130
                          DRIZZLE_TIME *l_time,
 
131
                          uint32_t flags)
222
132
{
223
133
  int was_cut;
224
 
  THD *thd= current_thd;
225
 
  timestamp_type ts_type;
226
 
  
 
134
  Session *session= current_session;
 
135
  enum enum_drizzle_timestamp_type ts_type;
 
136
 
227
137
  ts_type= str_to_datetime(str, length, l_time,
228
 
                           (flags | (thd->variables.sql_mode &
 
138
                           (flags | (session->variables.sql_mode &
229
139
                                     (MODE_INVALID_DATES |
230
140
                                      MODE_NO_ZERO_DATE))),
231
141
                           &was_cut);
232
142
  if (was_cut || ts_type <= DRIZZLE_TIMESTAMP_ERROR)
233
 
    make_truncated_value_warning(current_thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
234
 
                                 str, length, ts_type,  NullS);
 
143
    make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
144
                                 str, length, ts_type,  NULL);
235
145
  return ts_type;
236
146
}
237
147
 
238
148
 
239
 
/*
240
 
  Convert a datetime from broken-down DRIZZLE_TIME representation to corresponding 
241
 
  TIMESTAMP value.
242
 
 
243
 
  SYNOPSIS
244
 
    TIME_to_timestamp()
245
 
      thd             - current thread
246
 
      t               - datetime in broken-down representation, 
247
 
      in_dst_time_gap - pointer to bool which is set to true if t represents
248
 
                        value which doesn't exists (falls into the spring 
249
 
                        time-gap) or to false otherwise.
250
 
   
251
 
  RETURN
252
 
     Number seconds in UTC since start of Unix Epoch corresponding to t.
253
 
     0 - t contains datetime value which is out of TIMESTAMP range.
254
 
     
255
 
*/
256
 
my_time_t TIME_to_timestamp(THD *thd, const DRIZZLE_TIME *t, bool *in_dst_time_gap)
257
 
{
258
 
  my_time_t timestamp;
259
 
 
260
 
  *in_dst_time_gap= 0;
261
 
  thd->time_zone_used= 1;
262
 
 
263
 
  timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap);
264
 
  if (timestamp)
265
 
  {
266
 
    return timestamp;
267
 
  }
268
 
 
269
 
  /* If we are here we have range error. */
270
 
  return(0);
271
 
}
272
 
 
273
 
 
274
 
/*
275
 
  Convert a time string to a DRIZZLE_TIME struct and produce a warning
276
 
  if string was cut during conversion.
277
 
 
278
 
  NOTE
279
 
    See str_to_time() for more info.
280
 
*/
281
149
bool
282
 
str_to_time_with_warn(const char *str, uint length, DRIZZLE_TIME *l_time)
 
150
str_to_time_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time)
283
151
{
284
152
  int warning;
285
153
  bool ret_val= str_to_time(str, length, l_time, &warning);
286
154
  if (ret_val || warning)
287
 
    make_truncated_value_warning(current_thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
288
 
                                 str, length, DRIZZLE_TIMESTAMP_TIME, NullS);
 
155
    make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
156
                                 str, length, DRIZZLE_TIMESTAMP_TIME, NULL);
289
157
  return ret_val;
290
158
}
291
159
 
292
160
 
293
 
/*
294
 
  Convert a system time structure to TIME
295
 
*/
296
 
 
297
161
void localtime_to_TIME(DRIZZLE_TIME *to, struct tm *from)
298
162
{
299
163
  to->neg=0;
306
170
  to->second=   (int) from->tm_sec;
307
171
}
308
172
 
309
 
void calc_time_from_sec(DRIZZLE_TIME *to, long seconds, long microseconds)
310
 
{
311
 
  long t_seconds;
312
 
  // to->neg is not cleared, it may already be set to a useful value
313
 
  to->time_type= DRIZZLE_TIMESTAMP_TIME;
314
 
  to->year= 0;
315
 
  to->month= 0;
316
 
  to->day= 0;
317
 
  to->hour= seconds/3600L;
318
 
  t_seconds= seconds%3600L;
319
 
  to->minute= t_seconds/60L;
320
 
  to->second= t_seconds%60L;
321
 
  to->second_part= microseconds;
322
 
}
323
 
 
324
 
 
325
 
/*
326
 
  Parse a format string specification
327
 
 
328
 
  SYNOPSIS
329
 
    parse_date_time_format()
330
 
    format_type         Format of string (time, date or datetime)
331
 
    format_str          String to parse
332
 
    format_length       Length of string
333
 
    date_time_format    Format to fill in
334
 
 
335
 
  NOTES
336
 
    Fills in date_time_format->positions for all date time parts.
337
 
 
338
 
    positions marks the position for a datetime element in the format string.
339
 
    The position array elements are in the following order:
340
 
    YYYY-DD-MM HH-MM-DD.FFFFFF AM
341
 
    0    1  2  3  4  5  6      7
342
 
 
343
 
    If positions[0]= 5, it means that year will be the forth element to
344
 
    read from the parsed date string.
345
 
 
346
 
  RETURN
347
 
    0   ok
348
 
    1   error
349
 
*/
350
 
 
351
 
bool parse_date_time_format(timestamp_type format_type, 
352
 
                            const char *format, uint format_length,
353
 
                            DATE_TIME_FORMAT *date_time_format)
354
 
{
355
 
  uint offset= 0, separators= 0;
356
 
  const char *ptr= format, *format_str;
357
 
  const char *end= ptr+format_length;
358
 
  uchar *dt_pos= date_time_format->positions;
359
 
  /* need_p is set if we are using AM/PM format */
360
 
  bool need_p= 0, allow_separator= 0;
361
 
  ulong part_map= 0, separator_map= 0;
362
 
  const char *parts[16];
363
 
 
364
 
  date_time_format->time_separator= 0;
365
 
  date_time_format->flag= 0;                    // For future
366
 
 
367
 
  /*
368
 
    Fill position with 'dummy' arguments to found out if a format tag is
369
 
    used twice (This limit's the format to 255 characters, but this is ok)
370
 
  */
371
 
  dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]=
372
 
    dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= 255;
373
 
 
374
 
  for (; ptr != end; ptr++)
375
 
  {
376
 
    if (*ptr == '%' && ptr+1 != end)
377
 
    {
378
 
      uint position;
379
 
      switch (*++ptr) {
380
 
      case 'y':                                 // Year
381
 
      case 'Y':
382
 
        position= 0;
383
 
        break;
384
 
      case 'c':                                 // Month
385
 
      case 'm':
386
 
        position= 1;
387
 
        break;
388
 
      case 'd':
389
 
      case 'e':
390
 
        position= 2;
391
 
        break;
392
 
      case 'h':
393
 
      case 'I':
394
 
      case 'l':
395
 
        need_p= 1;                              // Need AM/PM
396
 
        /* Fall through */
397
 
      case 'k':
398
 
      case 'H':
399
 
        position= 3;
400
 
        break;
401
 
      case 'i':
402
 
        position= 4;
403
 
        break;
404
 
      case 's':
405
 
      case 'S':
406
 
        position= 5;
407
 
        break;
408
 
      case 'f':
409
 
        position= 6;
410
 
        if (dt_pos[5] != offset-1 || ptr[-2] != '.')
411
 
          return 1;                             // Wrong usage of %f
412
 
        break;
413
 
      case 'p':                                 // AM/PM
414
 
        if (offset == 0)                        // Can't be first
415
 
          return 0;
416
 
        position= 7;
417
 
        break;
418
 
      default:
419
 
        return 1;                               // Unknown controll char
420
 
      }
421
 
      if (dt_pos[position] != 255)              // Don't allow same tag twice
422
 
        return 1;
423
 
      parts[position]= ptr-1;
424
 
 
425
 
      /*
426
 
        If switching from time to date, ensure that all time parts
427
 
        are used
428
 
      */
429
 
      if (part_map && position <= 2 && !(part_map & (1 | 2 | 4)))
430
 
        offset=5;
431
 
      part_map|= (ulong) 1 << position;
432
 
      dt_pos[position]= offset++;
433
 
      allow_separator= 1;
434
 
    }
435
 
    else
436
 
    {
437
 
      /*
438
 
        Don't allow any characters in format as this could easily confuse
439
 
        the date reader
440
 
      */
441
 
      if (!allow_separator)
442
 
        return 1;                               // No separator here
443
 
      allow_separator= 0;                       // Don't allow two separators
444
 
      separators++;
445
 
      /* Store in separator_map which parts are punct characters */
446
 
      if (my_ispunct(&my_charset_utf8_general_ci, *ptr))
447
 
        separator_map|= (ulong) 1 << (offset-1);
448
 
      else if (!my_isspace(&my_charset_utf8_general_ci, *ptr))
449
 
        return 1;
450
 
    }
451
 
  }
452
 
 
453
 
  /* If no %f, specify it after seconds.  Move %p up, if necessary */
454
 
  if ((part_map & 32) && !(part_map & 64))
455
 
  {
456
 
    dt_pos[6]= dt_pos[5] +1;
457
 
    parts[6]= parts[5];                         // For later test in (need_p)
458
 
    if (dt_pos[6] == dt_pos[7])                 // Move %p one step up if used
459
 
      dt_pos[7]++;
460
 
  }
461
 
 
462
 
  /*
463
 
    Check that we have not used a non legal format specifier and that all
464
 
    format specifiers have been used
465
 
 
466
 
    The last test is to ensure that %p is used if and only if
467
 
    it's needed.
468
 
  */
469
 
  if ((format_type == DRIZZLE_TIMESTAMP_DATETIME &&
470
 
       !test_all_bits(part_map, (1 | 2 | 4 | 8 | 16 | 32))) ||
471
 
      (format_type == DRIZZLE_TIMESTAMP_DATE && part_map != (1 | 2 | 4)) ||
472
 
      (format_type == DRIZZLE_TIMESTAMP_TIME &&
473
 
       !test_all_bits(part_map, 8 | 16 | 32)) ||
474
 
      !allow_separator ||                       // %option should be last
475
 
      (need_p && dt_pos[6] +1 != dt_pos[7]) ||
476
 
      (need_p ^ (dt_pos[7] != 255)))
477
 
    return 1;
478
 
 
479
 
  if (dt_pos[6] != 255)                         // If fractional seconds
480
 
  {
481
 
    /* remove fractional seconds from later tests */
482
 
    uint pos= dt_pos[6] -1;
483
 
    /* Remove separator before %f from sep map */
484
 
    separator_map= ((separator_map & ((ulong) (1 << pos)-1)) |
485
 
                    ((separator_map & ~((ulong) (1 << pos)-1)) >> 1));
486
 
    if (part_map & 64)                        
487
 
    {
488
 
      separators--;                             // There is always a separator
489
 
      need_p= 1;                                // force use of separators
490
 
    }
491
 
  }
492
 
 
493
 
  /*
494
 
    Remove possible separator before %p from sep_map
495
 
    (This can either be at position 3, 4, 6 or 7) h.m.d.%f %p
496
 
  */
497
 
  if (dt_pos[7] != 255)
498
 
  {
499
 
    if (need_p && parts[7] != parts[6]+2)
500
 
      separators--;
501
 
  }     
502
 
  /*
503
 
    Calculate if %p is in first or last part of the datetime field
504
 
 
505
 
    At this point we have either %H-%i-%s %p 'year parts' or
506
 
    'year parts' &H-%i-%s %p" as %f was removed above
507
 
  */
508
 
  offset= dt_pos[6] <= 3 ? 3 : 6;
509
 
  /* Remove separator before %p from sep map */
510
 
  separator_map= ((separator_map & ((ulong) (1 << offset)-1)) |
511
 
                  ((separator_map & ~((ulong) (1 << offset)-1)) >> 1));
512
 
 
513
 
  format_str= 0;
514
 
  switch (format_type) {
515
 
  case DRIZZLE_TIMESTAMP_DATE:
516
 
    format_str= known_date_time_formats[INTERNAL_FORMAT].date_format;
517
 
    /* fall through */
518
 
  case DRIZZLE_TIMESTAMP_TIME:
519
 
    if (!format_str)
520
 
      format_str=known_date_time_formats[INTERNAL_FORMAT].time_format;
521
 
 
522
 
    /*
523
 
      If there is no separators, allow the internal format as we can read
524
 
      this.  If separators are used, they must be between each part
525
 
    */
526
 
    if (format_length == 6 && !need_p &&
527
 
        !my_strnncoll(&my_charset_bin,
528
 
                      (const uchar *) format, 6, 
529
 
                      (const uchar *) format_str, 6))
530
 
      return 0;
531
 
    if (separator_map == (1 | 2))
532
 
    {
533
 
      if (format_type == DRIZZLE_TIMESTAMP_TIME)
534
 
      {
535
 
        if (*(format+2) != *(format+5))
536
 
          break;                                // Error
537
 
        /* Store the character used for time formats */
538
 
        date_time_format->time_separator= *(format+2);
539
 
      }
540
 
      return 0;
541
 
    }
542
 
    break;
543
 
  case DRIZZLE_TIMESTAMP_DATETIME:
544
 
    /*
545
 
      If there is no separators, allow the internal format as we can read
546
 
      this.  If separators are used, they must be between each part.
547
 
      Between DATE and TIME we also allow space as separator
548
 
    */
549
 
    if ((format_length == 12 && !need_p &&
550
 
         !my_strnncoll(&my_charset_bin, 
551
 
                       (const uchar *) format, 12,
552
 
                       (const uchar*) known_date_time_formats[INTERNAL_FORMAT].datetime_format,
553
 
                       12)) ||
554
 
        (separators == 5 && separator_map == (1 | 2 | 8 | 16)))
555
 
      return 0;
556
 
    break;
557
 
  default:
558
 
    assert(1);
559
 
    break;
560
 
  }
561
 
  return 1;                                     // Error
562
 
}
563
 
 
564
 
 
565
 
/*
566
 
  Create a DATE_TIME_FORMAT object from a format string specification
567
 
 
568
 
  SYNOPSIS
569
 
    date_time_format_make()
570
 
    format_type         Format to parse (time, date or datetime)
571
 
    format_str          String to parse
572
 
    format_length       Length of string
573
 
 
574
 
  NOTES
575
 
    The returned object should be freed with my_free()
576
 
 
577
 
  RETURN
578
 
    NULL ponter:        Error
579
 
    new object
580
 
*/
581
 
 
582
 
DATE_TIME_FORMAT
583
 
*date_time_format_make(timestamp_type format_type,
584
 
                       const char *format_str, uint format_length)
585
 
{
586
 
  DATE_TIME_FORMAT tmp;
587
 
 
588
 
  if (format_length && format_length < 255 &&
589
 
      !parse_date_time_format(format_type, format_str,
590
 
                              format_length, &tmp))
591
 
  {
592
 
    tmp.format.str=    (char*) format_str;
593
 
    tmp.format.length= format_length;
594
 
    return date_time_format_copy((THD *)0, &tmp);
595
 
  }
596
 
  return 0;
597
 
}
598
 
 
599
 
 
600
 
/*
601
 
  Create a copy of a DATE_TIME_FORMAT object
602
 
 
603
 
  SYNOPSIS
604
 
    date_and_time_format_copy()
605
 
    thd                 Set if variable should be allocated in thread mem
606
 
    format              format to copy
607
 
 
608
 
  NOTES
609
 
    The returned object should be freed with my_free()
610
 
 
611
 
  RETURN
612
 
    NULL ponter:        Error
613
 
    new object
614
 
*/
615
 
 
616
 
DATE_TIME_FORMAT *date_time_format_copy(THD *thd, DATE_TIME_FORMAT *format)
617
 
{
618
 
  DATE_TIME_FORMAT *new_format;
619
 
  ulong length= sizeof(*format) + format->format.length + 1;
620
 
 
621
 
  if (thd)
622
 
    new_format= (DATE_TIME_FORMAT *) thd->alloc(length);
623
 
  else
624
 
    new_format=  (DATE_TIME_FORMAT *) my_malloc(length, MYF(MY_WME));
625
 
  if (new_format)
626
 
  {
627
 
    /* Put format string after current pos */
628
 
    new_format->format.str= (char*) (new_format+1);
629
 
    memcpy(new_format->positions, format->positions,
630
 
           sizeof(format->positions));
631
 
    new_format->time_separator= format->time_separator;
632
 
    /* We make the string null terminated for easy printf in SHOW VARIABLES */
633
 
    memcpy(new_format->format.str, format->format.str,
634
 
           format->format.length);
635
 
    new_format->format.str[format->format.length]= 0;
636
 
    new_format->format.length= format->format.length;
637
 
  }
638
 
  return new_format;
639
 
}
640
 
 
641
 
 
642
 
KNOWN_DATE_TIME_FORMAT known_date_time_formats[6]=
643
 
{
644
 
  {"USA", "%m.%d.%Y", "%Y-%m-%d %H.%i.%s", "%h:%i:%s %p" },
645
 
  {"JIS", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
646
 
  {"ISO", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
647
 
  {"EUR", "%d.%m.%Y", "%Y-%m-%d %H.%i.%s", "%H.%i.%s" },
648
 
  {"INTERNAL", "%Y%m%d",   "%Y%m%d%H%i%s", "%H%i%s" },
649
 
  { 0, 0, 0, 0 }
650
 
};
651
 
 
652
 
 
653
 
/*
654
 
   Return format string according format name.
655
 
   If name is unknown, result is NULL
656
 
*/
657
 
 
658
 
const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
659
 
                                     timestamp_type type)
660
 
{
661
 
  switch (type) {
662
 
  case DRIZZLE_TIMESTAMP_DATE:
663
 
    return format->date_format;
664
 
  case DRIZZLE_TIMESTAMP_DATETIME:
665
 
    return format->datetime_format;
666
 
  case DRIZZLE_TIMESTAMP_TIME:
667
 
    return format->time_format;
668
 
  default:
669
 
    assert(0);                          // Impossible
670
 
    return 0;
671
 
  }
672
 
}
673
 
 
674
 
/****************************************************************************
675
 
  Functions to create default time/date/datetime strings
676
 
 
677
 
  NOTE:
678
 
    For the moment the DATE_TIME_FORMAT argument is ignored becasue
679
 
    MySQL doesn't support comparing of date/time/datetime strings that
680
 
    are not in arbutary order as dates are compared as strings in some
681
 
    context)
682
 
    This functions don't check that given DRIZZLE_TIME structure members are
683
 
    in valid range. If they are not, return value won't reflect any 
684
 
    valid date either. Additionally, make_time doesn't take into
685
 
    account time->day member: it's assumed that days have been converted
686
 
    to hours already.
687
 
****************************************************************************/
688
 
 
689
 
void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)),
690
 
               const DRIZZLE_TIME *l_time, String *str)
691
 
{
692
 
  uint length= (uint) my_time_to_str(l_time, (char*) str->ptr());
693
 
  str->length(length);
694
 
  str->set_charset(&my_charset_bin);
695
 
}
696
 
 
697
 
 
698
 
void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)),
699
 
               const DRIZZLE_TIME *l_time, String *str)
700
 
{
701
 
  uint length= (uint) my_date_to_str(l_time, (char*) str->ptr());
702
 
  str->length(length);
703
 
  str->set_charset(&my_charset_bin);
704
 
}
705
 
 
706
 
 
707
 
void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)),
708
 
                   const DRIZZLE_TIME *l_time, String *str)
709
 
{
710
 
  uint length= (uint) my_datetime_to_str(l_time, (char*) str->ptr());
711
 
  str->length(length);
712
 
  str->set_charset(&my_charset_bin);
713
 
}
714
 
 
715
 
 
716
 
void make_truncated_value_warning(THD *thd, DRIZZLE_ERROR::enum_warning_level level,
 
173
void make_date(const DRIZZLE_TIME *l_time, String *str)
 
174
{
 
175
  str->alloc(MAX_DATE_STRING_REP_LENGTH);
 
176
  uint32_t length= (uint32_t) my_date_to_str(l_time, str->c_ptr());
 
177
  str->length(length);
 
178
  str->set_charset(&my_charset_bin);
 
179
}
 
180
 
 
181
 
 
182
void make_datetime(const DRIZZLE_TIME *l_time, String *str)
 
183
{
 
184
  str->alloc(MAX_DATE_STRING_REP_LENGTH);
 
185
  uint32_t length= (uint32_t) my_datetime_to_str(l_time, str->c_ptr());
 
186
  str->length(length);
 
187
  str->set_charset(&my_charset_bin);
 
188
}
 
189
 
 
190
 
 
191
void make_truncated_value_warning(Session *session, 
 
192
                                  DRIZZLE_ERROR::enum_warning_level level,
717
193
                                  const char *str_val,
718
 
                                  uint str_length, timestamp_type time_type,
 
194
                                                          uint32_t str_length,
 
195
                                  enum enum_drizzle_timestamp_type time_type,
719
196
                                  const char *field_name)
720
197
{
721
198
  char warn_buff[DRIZZLE_ERRMSG_SIZE];
727
204
  str[str_length]= 0;               // Ensure we have end 0 for snprintf
728
205
 
729
206
  switch (time_type) {
730
 
    case DRIZZLE_TIMESTAMP_DATE: 
 
207
    case DRIZZLE_TIMESTAMP_DATE:
731
208
      type_str= "date";
732
209
      break;
733
210
    case DRIZZLE_TIMESTAMP_TIME:
742
219
    cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
743
220
                       ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
744
221
                       type_str, str.c_ptr(), field_name,
745
 
                       (ulong) thd->row_count);
 
222
                       (uint32_t) session->row_count);
746
223
  else
747
224
  {
748
225
    if (time_type > DRIZZLE_TIMESTAMP_ERROR)
753
230
      cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
754
231
                         ER(ER_WRONG_VALUE), type_str, str.c_ptr());
755
232
  }
756
 
  push_warning(thd, level,
 
233
  push_warning(session, level,
757
234
               ER_TRUNCATED_WRONG_VALUE, warn_buff);
758
235
}
759
236
 
760
 
/* Daynumber from year 0 to 9999-12-31 */
761
 
#define MAX_DAY_NUMBER 3652424L
762
 
 
763
 
bool date_add_interval(DRIZZLE_TIME *ltime, interval_type int_type, INTERVAL interval)
764
 
{
765
 
  long period, sign;
766
 
 
767
 
  ltime->neg= 0;
768
 
 
769
 
  sign= (interval.neg ? -1 : 1);
770
 
 
771
 
  switch (int_type) {
772
 
  case INTERVAL_SECOND:
773
 
  case INTERVAL_SECOND_MICROSECOND:
774
 
  case INTERVAL_MICROSECOND:
775
 
  case INTERVAL_MINUTE:
776
 
  case INTERVAL_HOUR:
777
 
  case INTERVAL_MINUTE_MICROSECOND:
778
 
  case INTERVAL_MINUTE_SECOND:
779
 
  case INTERVAL_HOUR_MICROSECOND:
780
 
  case INTERVAL_HOUR_SECOND:
781
 
  case INTERVAL_HOUR_MINUTE:
782
 
  case INTERVAL_DAY_MICROSECOND:
783
 
  case INTERVAL_DAY_SECOND:
784
 
  case INTERVAL_DAY_MINUTE:
785
 
  case INTERVAL_DAY_HOUR:
786
 
  {
787
 
    int64_t sec, days, daynr, microseconds, extra_sec;
788
 
    ltime->time_type= DRIZZLE_TIMESTAMP_DATETIME; // Return full date
789
 
    microseconds= ltime->second_part + sign*interval.second_part;
790
 
    extra_sec= microseconds/1000000L;
791
 
    microseconds= microseconds%1000000L;
792
 
 
793
 
    sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
794
 
         ltime->second +
795
 
         sign* (int64_t) (interval.day*3600*24L +
796
 
                           interval.hour*3600LL+interval.minute*60LL+
797
 
                           interval.second))+ extra_sec;
798
 
    if (microseconds < 0)
799
 
    {
800
 
      microseconds+= 1000000LL;
801
 
      sec--;
802
 
    }
803
 
    days= sec/(3600*24LL);
804
 
    sec-= days*3600*24LL;
805
 
    if (sec < 0)
806
 
    {
807
 
      days--;
808
 
      sec+= 3600*24LL;
809
 
    }
810
 
    ltime->second_part= (uint) microseconds;
811
 
    ltime->second= (uint) (sec % 60);
812
 
    ltime->minute= (uint) (sec/60 % 60);
813
 
    ltime->hour=   (uint) (sec/3600);
814
 
    daynr= calc_daynr(ltime->year,ltime->month,1) + days;
815
 
    /* Day number from year 0 to 9999-12-31 */
816
 
    if ((uint64_t) daynr > MAX_DAY_NUMBER)
817
 
      goto invalid_date;
818
 
    get_date_from_daynr((long) daynr, &ltime->year, &ltime->month,
819
 
                        &ltime->day);
820
 
    break;
821
 
  }
822
 
  case INTERVAL_DAY:
823
 
  case INTERVAL_WEEK:
824
 
    period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
825
 
             sign * (long) interval.day);
826
 
    /* Daynumber from year 0 to 9999-12-31 */
827
 
    if ((ulong) period > MAX_DAY_NUMBER)
828
 
      goto invalid_date;
829
 
    get_date_from_daynr((long) period,&ltime->year,&ltime->month,&ltime->day);
830
 
    break;
831
 
  case INTERVAL_YEAR:
832
 
    ltime->year+= sign * (long) interval.year;
833
 
    if ((ulong) ltime->year >= 10000L)
834
 
      goto invalid_date;
835
 
    if (ltime->month == 2 && ltime->day == 29 &&
836
 
        calc_days_in_year(ltime->year) != 366)
837
 
      ltime->day=28;                            // Was leap-year
838
 
    break;
839
 
  case INTERVAL_YEAR_MONTH:
840
 
  case INTERVAL_QUARTER:
841
 
  case INTERVAL_MONTH:
842
 
    period= (ltime->year*12 + sign * (long) interval.year*12 +
843
 
             ltime->month-1 + sign * (long) interval.month);
844
 
    if ((ulong) period >= 120000L)
845
 
      goto invalid_date;
846
 
    ltime->year= (uint) (period / 12);
847
 
    ltime->month= (uint) (period % 12L)+1;
848
 
    /* Adjust day if the new month doesn't have enough days */
849
 
    if (ltime->day > days_in_month[ltime->month-1])
850
 
    {
851
 
      ltime->day = days_in_month[ltime->month-1];
852
 
      if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
853
 
        ltime->day++;                           // Leap-year
854
 
    }
855
 
    break;
856
 
  default:
857
 
    goto null_date;
858
 
  }
859
 
 
860
 
  return 0;                                     // Ok
861
 
 
862
 
invalid_date:
863
 
  push_warning_printf(current_thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
864
 
                      ER_DATETIME_FUNCTION_OVERFLOW,
865
 
                      ER(ER_DATETIME_FUNCTION_OVERFLOW),
866
 
                      "datetime");
867
 
null_date:
868
 
  return 1;
869
 
}
870
 
 
871
 
 
872
 
/*
873
 
  Calculate difference between two datetime values as seconds + microseconds.
874
 
 
875
 
  SYNOPSIS
876
 
    calc_time_diff()
877
 
      l_time1         - TIME/DATE/DATETIME value
878
 
      l_time2         - TIME/DATE/DATETIME value
879
 
      l_sign          - 1 absolute values are substracted,
880
 
                        -1 absolute values are added.
881
 
      seconds_out     - Out parameter where difference between
882
 
                        l_time1 and l_time2 in seconds is stored.
883
 
      microseconds_out- Out parameter where microsecond part of difference
884
 
                        between l_time1 and l_time2 is stored.
885
 
 
886
 
  NOTE
887
 
    This function calculates difference between l_time1 and l_time2 absolute
888
 
    values. So one should set l_sign and correct result if he want to take
889
 
    signs into account (i.e. for DRIZZLE_TIME values).
890
 
 
891
 
  RETURN VALUES
892
 
    Returns sign of difference.
893
 
    1 means negative result
894
 
    0 means positive result
895
 
 
896
 
*/
897
237
 
898
238
bool
899
239
calc_time_diff(DRIZZLE_TIME *l_time1, DRIZZLE_TIME *l_time2, int l_sign, int64_t *seconds_out,
912
252
    days= (long)l_time1->day - l_sign * (long)l_time2->day;
913
253
  else
914
254
  {
915
 
    days= calc_daynr((uint) l_time1->year,
916
 
                     (uint) l_time1->month,
917
 
                     (uint) l_time1->day);
 
255
    days= calc_daynr((uint32_t) l_time1->year,
 
256
                     (uint32_t) l_time1->month,
 
257
                     (uint32_t) l_time1->day);
918
258
    if (l_time2->time_type == DRIZZLE_TIMESTAMP_TIME)
919
259
      days-= l_sign * (long)l_time2->day;
920
260
    else
921
 
      days-= l_sign*calc_daynr((uint) l_time2->year,
922
 
                               (uint) l_time2->month,
923
 
                               (uint) l_time2->day);
 
261
      days-= l_sign*calc_daynr((uint32_t) l_time2->year,
 
262
                               (uint32_t) l_time2->month,
 
263
                               (uint32_t) l_time2->day);
924
264
  }
925
265
 
926
 
  microseconds= ((int64_t)days*86400LL +
 
266
  microseconds= ((int64_t)days*86400L +
927
267
                 (int64_t)(l_time1->hour*3600L +
928
268
                            l_time1->minute*60L +
929
269
                            l_time1->second) -
930
270
                 l_sign*(int64_t)(l_time2->hour*3600L +
931
271
                                   l_time2->minute*60L +
932
 
                                   l_time2->second)) * 1000000LL +
 
272
                                   l_time2->second)) * 1000000L +
933
273
                (int64_t)l_time1->second_part -
934
274
                l_sign*(int64_t)l_time2->second_part;
935
275
 
944
284
  return neg;
945
285
}
946
286
 
947
 
 
948
 
/*
949
 
  Compares 2 DRIZZLE_TIME structures
950
 
 
951
 
  SYNOPSIS
952
 
    my_time_compare()
953
 
 
954
 
      a - first time
955
 
      b - second time
956
 
 
957
 
  RETURN VALUE
958
 
   -1   - a < b
959
 
    0   - a == b
960
 
    1   - a > b
961
 
 
962
 
  NOTES
963
 
    TIME.second_part is not considered during comparison
964
 
*/
965
 
 
966
 
int
967
 
my_time_compare(DRIZZLE_TIME *a, DRIZZLE_TIME *b)
968
 
{
969
 
  uint64_t a_t= TIME_to_uint64_t_datetime(a);
970
 
  uint64_t b_t= TIME_to_uint64_t_datetime(b);
971
 
 
972
 
  if (a_t > b_t)
973
 
    return 1;
974
 
  else if (a_t < b_t)
975
 
    return -1;
976
 
 
977
 
  return 0;
978
 
}
979
 
 
980
 
#endif
 
287
} /* namespace drizzled */