~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/time.cc

  • Committer: Monty Taylor
  • Date: 2008-08-01 22:33:44 UTC
  • mto: (236.1.42 codestyle)
  • mto: This revision was merged to the branch mainline in revision 261.
  • Revision ID: monty@inaugust.com-20080801223344-vzhlflfmtijp1imv
First pass at gettexizing the error messages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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, Inc.
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
 
 */
 
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 */
19
15
 
20
16
 
21
17
/* Functions to handle date and time */
22
18
 
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
 
 
 
19
#include "mysql_priv.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 .... */
35
63
 
36
64
int calc_weekday(long daynr,bool sunday_first_day_of_week)
37
65
{
38
66
  return ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
39
67
}
40
68
 
41
 
 
42
 
uint32_t calc_week(type::Time *l_time, uint32_t week_behaviour, uint32_t *year)
 
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)
43
99
{
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);
 
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);
47
103
  bool monday_first= test(week_behaviour & WEEK_MONDAY_FIRST);
48
104
  bool week_year= test(week_behaviour & WEEK_YEAR);
49
105
  bool first_weekday= test(week_behaviour & WEEK_FIRST_WEEKDAY);
50
106
 
51
 
  uint32_t weekday= calc_weekday(first_daynr, !monday_first);
 
107
  uint weekday=calc_weekday(first_daynr, !monday_first);
52
108
  *year=l_time->year;
53
109
 
54
110
  if (l_time->month == 1 && l_time->day <= 7-weekday)
79
135
  return days/7+1;
80
136
}
81
137
 
 
138
        /* Change a daynr to year, month and day */
 
139
        /* Daynr 0 is returned as date 00.00.00 */
82
140
 
83
 
void get_date_from_daynr(long daynr,
84
 
                         uint32_t *ret_year,
85
 
                         uint32_t *ret_month,
86
 
                                           uint32_t *ret_day)
 
141
void get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month,
 
142
                         uint *ret_day)
87
143
{
88
 
  uint32_t year,temp,leap_day,day_of_year,days_in_year;
89
 
  unsigned char *month_pos;
 
144
  uint year,temp,leap_day,day_of_year,days_in_year;
 
145
  uchar *month_pos;
90
146
 
91
147
  if (daynr <= 365L || daynr >= 3652500)
92
148
  {                                             /* Fix if wrong daynr */
94
150
  }
95
151
  else
96
152
  {
97
 
    year= (uint32_t) (daynr*100 / 36525L);
 
153
    year= (uint) (daynr*100 / 36525L);
98
154
    temp=(((year-1)/100+1)*3)/4;
99
 
    day_of_year=(uint32_t) (daynr - (long) year * 365L) - (year-1)/4 +temp;
 
155
    day_of_year=(uint) (daynr - (long) year * 365L) - (year-1)/4 +temp;
100
156
    while (day_of_year > (days_in_year= calc_days_in_year(year)))
101
157
    {
102
158
      day_of_year-=days_in_year;
107
163
    {
108
164
      if (day_of_year > 31+28)
109
165
      {
110
 
        day_of_year--;
111
 
        if (day_of_year == 31+28)
112
 
          leap_day=1;           /* Handle leapyears leapday */
 
166
        day_of_year--;
 
167
        if (day_of_year == 31+28)
 
168
          leap_day=1;           /* Handle leapyears leapday */
113
169
      }
114
170
    }
115
171
    *ret_month=1;
116
172
    for (month_pos= days_in_month ;
117
 
         day_of_year > (uint32_t) *month_pos ;
118
 
         day_of_year-= *(month_pos++), (*ret_month)++)
 
173
         day_of_year > (uint) *month_pos ;
 
174
         day_of_year-= *(month_pos++), (*ret_month)++)
119
175
      ;
120
176
    *ret_year=year;
121
177
    *ret_day=day_of_year+leap_day;
123
179
  return;
124
180
}
125
181
 
126
 
 
127
 
type::timestamp_t str_to_datetime_with_warn(Session *session,
128
 
                                            const char *str, 
129
 
                                            uint32_t length, 
130
 
                                            type::Time *l_time,
131
 
                                            uint32_t flags)
132
 
{
133
 
  type::cut_t was_cut= type::VALID;
134
 
  type::timestamp_t ts_type;
135
 
 
136
 
  ts_type= l_time->store(str, length,
137
 
                         (flags | (session->variables.sql_mode &
138
 
                                   (MODE_INVALID_DATES |
139
 
                                    MODE_NO_ZERO_DATE))),
140
 
                         was_cut);
141
 
  if (was_cut || ts_type <= type::DRIZZLE_TIMESTAMP_ERROR)
142
 
    make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
143
 
                                 str, length, ts_type,  NULL);
144
 
 
 
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)
 
222
{
 
223
  int was_cut;
 
224
  THD *thd= current_thd;
 
225
  timestamp_type ts_type;
 
226
  
 
227
  ts_type= str_to_datetime(str, length, l_time,
 
228
                           (flags | (thd->variables.sql_mode &
 
229
                                     (MODE_INVALID_DATES |
 
230
                                      MODE_NO_ZERO_DATE))),
 
231
                           &was_cut);
 
232
  if (was_cut || ts_type <= DRIZZLE_TIMESTAMP_ERROR)
 
233
    make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
234
                                 str, length, ts_type,  NullS);
145
235
  return ts_type;
146
236
}
147
237
 
148
238
 
 
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
*/
149
281
bool
150
 
str_to_time_with_warn(Session *session, const char *str, uint32_t length, type::Time *l_time)
 
282
str_to_time_with_warn(const char *str, uint length, DRIZZLE_TIME *l_time)
151
283
{
152
284
  int warning;
153
 
  bool ret_val= l_time->store(str, length, warning, type::DRIZZLE_TIMESTAMP_TIME);
 
285
  bool ret_val= str_to_time(str, length, l_time, &warning);
154
286
  if (ret_val || warning)
155
 
    make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
156
 
                                 str, length, type::DRIZZLE_TIMESTAMP_TIME, NULL);
 
287
    make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
288
                                 str, length, DRIZZLE_TIMESTAMP_TIME, NullS);
157
289
  return ret_val;
158
290
}
159
291
 
160
292
 
161
 
void make_truncated_value_warning(Session *session, 
162
 
                                  DRIZZLE_ERROR::enum_warning_level level,
 
293
/*
 
294
  Convert a system time structure to TIME
 
295
*/
 
296
 
 
297
void localtime_to_TIME(DRIZZLE_TIME *to, struct tm *from)
 
298
{
 
299
  to->neg=0;
 
300
  to->second_part=0;
 
301
  to->year=     (int) ((from->tm_year+1900) % 10000);
 
302
  to->month=    (int) from->tm_mon+1;
 
303
  to->day=      (int) from->tm_mday;
 
304
  to->hour=     (int) from->tm_hour;
 
305
  to->minute=   (int) from->tm_min;
 
306
  to->second=   (int) from->tm_sec;
 
307
}
 
308
 
 
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_latin1, *ptr))
 
447
        separator_map|= (ulong) 1 << (offset-1);
 
448
      else if (!my_isspace(&my_charset_latin1, *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((char*) new_format->positions, (char*) 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((char*) 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, MYSQL_ERROR::enum_warning_level level,
163
717
                                  const char *str_val,
164
 
                                                          uint32_t str_length,
165
 
                                  type::timestamp_t time_type,
 
718
                                  uint str_length, timestamp_type time_type,
166
719
                                  const char *field_name)
167
720
{
168
 
  char warn_buff[DRIZZLE_ERRMSG_SIZE];
 
721
  char warn_buff[MYSQL_ERRMSG_SIZE];
169
722
  const char *type_str;
170
 
  CHARSET_INFO *cs= &my_charset_utf8_general_ci;
 
723
  CHARSET_INFO *cs= &my_charset_latin1;
171
724
  char buff[128];
172
725
  String str(buff,(uint32_t) sizeof(buff), system_charset_info);
173
726
  str.copy(str_val, str_length, system_charset_info);
174
727
  str[str_length]= 0;               // Ensure we have end 0 for snprintf
175
728
 
176
729
  switch (time_type) {
177
 
  case type::DRIZZLE_TIMESTAMP_DATE:
178
 
    type_str= "date";
179
 
    break;
180
 
 
181
 
  case type::DRIZZLE_TIMESTAMP_TIME:
182
 
    type_str= "time";
183
 
    break;
184
 
 
185
 
  case type::DRIZZLE_TIMESTAMP_DATETIME:  // FALLTHROUGH
186
 
  default:
187
 
    type_str= "datetime";
188
 
    break;
 
730
    case DRIZZLE_TIMESTAMP_DATE: 
 
731
      type_str= "date";
 
732
      break;
 
733
    case DRIZZLE_TIMESTAMP_TIME:
 
734
      type_str= "time";
 
735
      break;
 
736
    case DRIZZLE_TIMESTAMP_DATETIME:  // FALLTHROUGH
 
737
    default:
 
738
      type_str= "datetime";
 
739
      break;
189
740
  }
190
 
 
191
741
  if (field_name)
192
 
  {
193
742
    cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
194
743
                       ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
195
744
                       type_str, str.c_ptr(), field_name,
196
 
                       (uint32_t) session->row_count);
197
 
  }
 
745
                       (ulong) thd->row_count);
198
746
  else
199
747
  {
200
 
    if (time_type > type::DRIZZLE_TIMESTAMP_ERROR)
201
 
    {
 
748
    if (time_type > DRIZZLE_TIMESTAMP_ERROR)
202
749
      cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
203
750
                         ER(ER_TRUNCATED_WRONG_VALUE),
204
751
                         type_str, str.c_ptr());
205
 
    }
206
752
    else
207
 
    {
208
753
      cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
209
754
                         ER(ER_WRONG_VALUE), type_str, str.c_ptr());
210
 
    }
211
755
  }
212
 
  push_warning(session, level,
 
756
  push_warning(thd, level,
213
757
               ER_TRUNCATED_WRONG_VALUE, warn_buff);
214
758
}
215
759
 
 
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, MYSQL_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
*/
216
897
 
217
898
bool
218
 
calc_time_diff(type::Time *l_time1, type::Time *l_time2, int l_sign, int64_t *seconds_out,
 
899
calc_time_diff(DRIZZLE_TIME *l_time1, DRIZZLE_TIME *l_time2, int l_sign, int64_t *seconds_out,
219
900
               long *microseconds_out)
220
901
{
221
902
  long days;
227
908
    the second argument should be TIMESTAMP_TIME also.
228
909
    We should check it before calc_time_diff call.
229
910
  */
230
 
  if (l_time1->time_type == type::DRIZZLE_TIMESTAMP_TIME)  // Time value
 
911
  if (l_time1->time_type == DRIZZLE_TIMESTAMP_TIME)  // Time value
231
912
    days= (long)l_time1->day - l_sign * (long)l_time2->day;
232
913
  else
233
914
  {
234
 
    days= calc_daynr((uint32_t) l_time1->year,
235
 
                     (uint32_t) l_time1->month,
236
 
                     (uint32_t) l_time1->day);
237
 
    if (l_time2->time_type == type::DRIZZLE_TIMESTAMP_TIME)
 
915
    days= calc_daynr((uint) l_time1->year,
 
916
                     (uint) l_time1->month,
 
917
                     (uint) l_time1->day);
 
918
    if (l_time2->time_type == DRIZZLE_TIMESTAMP_TIME)
238
919
      days-= l_sign * (long)l_time2->day;
239
920
    else
240
 
      days-= l_sign*calc_daynr((uint32_t) l_time2->year,
241
 
                               (uint32_t) l_time2->month,
242
 
                               (uint32_t) l_time2->day);
 
921
      days-= l_sign*calc_daynr((uint) l_time2->year,
 
922
                               (uint) l_time2->month,
 
923
                               (uint) l_time2->day);
243
924
  }
244
925
 
245
 
  microseconds= ((int64_t)days*86400L +
 
926
  microseconds= ((int64_t)days*86400LL +
246
927
                 (int64_t)(l_time1->hour*3600L +
247
 
                           l_time1->minute*60L +
248
 
                           l_time1->second) -
 
928
                            l_time1->minute*60L +
 
929
                            l_time1->second) -
249
930
                 l_sign*(int64_t)(l_time2->hour*3600L +
250
 
                                  l_time2->minute*60L +
251
 
                                  l_time2->second)) * 1000000L +
252
 
    (int64_t)l_time1->second_part -
253
 
    l_sign*(int64_t)l_time2->second_part;
 
931
                                   l_time2->minute*60L +
 
932
                                   l_time2->second)) * 1000000LL +
 
933
                (int64_t)l_time1->second_part -
 
934
                l_sign*(int64_t)l_time2->second_part;
254
935
 
255
936
  neg= 0;
256
937
  if (microseconds < 0)
263
944
  return neg;
264
945
}
265
946
 
266
 
} /* namespace drizzled */
 
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