~drizzle-trunk/drizzle/development

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