~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>
584.1.15 by Monty Taylor
The mega-patch from hell. Renamed sql_class to session (since that's what it is) and removed it and field and table from common_includes.
27
#include <drizzled/session.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.
28
29
/* Some functions to calculate dates */
1 by brian
clean slate
30
31
#ifndef TESTTIME
32
33
/*
34
  Name description of interval names used in statements.
35
36
  'interval_type_to_name' is ordered and sorted on interval size and
37
  interval complexity.
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
38
  Order of elements in 'interval_type_to_name' should correspond to
1 by brian
clean slate
39
  the order of elements in 'interval_type' enum
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
40
1 by brian
clean slate
41
  See also interval_type, interval_names
42
*/
43
44
LEX_STRING interval_type_to_name[INTERVAL_LAST] = {
45
  { C_STRING_WITH_LEN("YEAR")},
46
  { C_STRING_WITH_LEN("QUARTER")},
47
  { C_STRING_WITH_LEN("MONTH")},
48
  { C_STRING_WITH_LEN("WEEK")},
49
  { C_STRING_WITH_LEN("DAY")},
50
  { C_STRING_WITH_LEN("HOUR")},
51
  { C_STRING_WITH_LEN("MINUTE")},
52
  { C_STRING_WITH_LEN("SECOND")},
53
  { C_STRING_WITH_LEN("MICROSECOND")},
54
  { C_STRING_WITH_LEN("YEAR_MONTH")},
55
  { C_STRING_WITH_LEN("DAY_HOUR")},
56
  { C_STRING_WITH_LEN("DAY_MINUTE")},
57
  { C_STRING_WITH_LEN("DAY_SECOND")},
58
  { C_STRING_WITH_LEN("HOUR_MINUTE")},
59
  { C_STRING_WITH_LEN("HOUR_SECOND")},
60
  { C_STRING_WITH_LEN("MINUTE_SECOND")},
61
  { C_STRING_WITH_LEN("DAY_MICROSECOND")},
62
  { C_STRING_WITH_LEN("HOUR_MICROSECOND")},
63
  { C_STRING_WITH_LEN("MINUTE_MICROSECOND")},
64
  { C_STRING_WITH_LEN("SECOND_MICROSECOND")}
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
65
};
1 by brian
clean slate
66
67
	/* Calc weekday from daynr */
68
	/* Returns 0 for monday, 1 for tuesday .... */
69
70
int calc_weekday(long daynr,bool sunday_first_day_of_week)
71
{
51.1.71 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
72
  return ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
1 by brian
clean slate
73
}
74
75
/*
76
  The bits in week_format has the following meaning:
77
   WEEK_MONDAY_FIRST (0)  If not set	Sunday is first day of week
78
      		   	  If set	Monday is first day of week
79
   WEEK_YEAR (1)	  If not set	Week is in range 0-53
80
81
   	Week 0 is returned for the the last week of the previous year (for
82
	a date at start of january) In this case one can get 53 for the
83
	first week of next year.  This flag ensures that the week is
84
	relevant for the given year. Note that this flag is only
85
	releveant if WEEK_JANUARY is not set.
86
87
			  If set	 Week is in range 1-53.
88
89
	In this case one may get week 53 for a date in January (when
90
	the week is that last week of previous year) and week 1 for a
91
	date in December.
92
93
  WEEK_FIRST_WEEKDAY (2)  If not set	Weeks are numbered according
94
			   		to ISO 8601:1988
95
			  If set	The week that contains the first
96
					'first-day-of-week' is week 1.
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
97
1 by brian
clean slate
98
	ISO 8601:1988 means that if the week containing January 1 has
99
	four or more days in the new year, then it is week 1;
100
	Otherwise it is the last week of the previous year, and the
101
	next week is week 1.
102
*/
103
482 by Brian Aker
Remove uint.
104
uint32_t calc_week(DRIZZLE_TIME *l_time, uint32_t week_behaviour, uint32_t *year)
1 by brian
clean slate
105
{
482 by Brian Aker
Remove uint.
106
  uint32_t days;
520.1.7 by Brian Aker
More ulong fixes (including a bug on row return on error)
107
  uint32_t daynr= calc_daynr(l_time->year,l_time->month,l_time->day);
108
  uint32_t first_daynr= calc_daynr(l_time->year,1,1);
1 by brian
clean slate
109
  bool monday_first= test(week_behaviour & WEEK_MONDAY_FIRST);
110
  bool week_year= test(week_behaviour & WEEK_YEAR);
111
  bool first_weekday= test(week_behaviour & WEEK_FIRST_WEEKDAY);
112
482 by Brian Aker
Remove uint.
113
  uint32_t weekday=calc_weekday(first_daynr, !monday_first);
1 by brian
clean slate
114
  *year=l_time->year;
115
116
  if (l_time->month == 1 && l_time->day <= 7-weekday)
117
  {
118
    if ((!week_year) && ((first_weekday && weekday != 0) || (!first_weekday && weekday >= 4)))
119
      return 0;
120
    week_year= 1;
121
    (*year)--;
122
    first_daynr-= (days=calc_days_in_year(*year));
123
    weekday= (weekday + 53*7- days) % 7;
124
  }
125
126
  if ((first_weekday && weekday != 0) ||
127
      (!first_weekday && weekday >= 4))
128
    days= daynr - (first_daynr+ (7-weekday));
129
  else
130
    days= daynr - (first_daynr - weekday);
131
132
  if (week_year && days >= 52*7)
133
  {
134
    weekday= (weekday + calc_days_in_year(*year)) % 7;
135
    if ((!first_weekday && weekday < 4) || (first_weekday && weekday == 0))
136
    {
137
      (*year)++;
138
      return 1;
139
    }
140
  }
141
  return days/7+1;
142
}
143
144
	/* Change a daynr to year, month and day */
145
	/* Daynr 0 is returned as date 00.00.00 */
146
482 by Brian Aker
Remove uint.
147
void get_date_from_daynr(long daynr,uint32_t *ret_year,uint32_t *ret_month,
148
			 uint32_t *ret_day)
1 by brian
clean slate
149
{
482 by Brian Aker
Remove uint.
150
  uint32_t year,temp,leap_day,day_of_year,days_in_year;
481 by Brian Aker
Remove all of uchar.
151
  unsigned char *month_pos;
1 by brian
clean slate
152
153
  if (daynr <= 365L || daynr >= 3652500)
154
  {						/* Fix if wrong daynr */
155
    *ret_year= *ret_month = *ret_day =0;
156
  }
157
  else
158
  {
895 by Brian Aker
Completion (?) of uint conversion.
159
    year= (uint32_t) (daynr*100 / 36525L);
1 by brian
clean slate
160
    temp=(((year-1)/100+1)*3)/4;
895 by Brian Aker
Completion (?) of uint conversion.
161
    day_of_year=(uint32_t) (daynr - (long) year * 365L) - (year-1)/4 +temp;
1 by brian
clean slate
162
    while (day_of_year > (days_in_year= calc_days_in_year(year)))
163
    {
164
      day_of_year-=days_in_year;
165
      (year)++;
166
    }
167
    leap_day=0;
168
    if (days_in_year == 366)
169
    {
170
      if (day_of_year > 31+28)
171
      {
172
	day_of_year--;
173
	if (day_of_year == 31+28)
174
	  leap_day=1;		/* Handle leapyears leapday */
175
      }
176
    }
177
    *ret_month=1;
178
    for (month_pos= days_in_month ;
895 by Brian Aker
Completion (?) of uint conversion.
179
	 day_of_year > (uint32_t) *month_pos ;
1 by brian
clean slate
180
	 day_of_year-= *(month_pos++), (*ret_month)++)
181
      ;
182
    *ret_year=year;
183
    *ret_day=day_of_year+leap_day;
184
  }
51.1.71 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
185
  return;
1 by brian
clean slate
186
}
187
188
/*
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
189
  Convert a timestamp string to a DRIZZLE_TIME value and produce a warning
1 by brian
clean slate
190
  if string was truncated during conversion.
191
192
  NOTE
193
    See description of str_to_datetime() for more information.
194
*/
195
398.1.1 by Monty Taylor
Remove typedef enum enum_drizzle_timestamp_type timestamp_type;
196
enum enum_drizzle_timestamp_type
482 by Brian Aker
Remove uint.
197
str_to_datetime_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time,
198
                          uint32_t flags)
1 by brian
clean slate
199
{
200
  int was_cut;
520.1.22 by Brian Aker
Second pass of thd cleanup
201
  Session *session= current_session;
398.1.1 by Monty Taylor
Remove typedef enum enum_drizzle_timestamp_type timestamp_type;
202
  enum enum_drizzle_timestamp_type ts_type;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
203
1 by brian
clean slate
204
  ts_type= str_to_datetime(str, length, l_time,
520.1.22 by Brian Aker
Second pass of thd cleanup
205
                           (flags | (session->variables.sql_mode &
1 by brian
clean slate
206
                                     (MODE_INVALID_DATES |
207
                                      MODE_NO_ZERO_DATE))),
208
                           &was_cut);
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
209
  if (was_cut || ts_type <= DRIZZLE_TIMESTAMP_ERROR)
520.1.22 by Brian Aker
Second pass of thd cleanup
210
    make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
461 by Monty Taylor
Removed NullS. bu-bye.
211
                                 str, length, ts_type,  NULL);
1 by brian
clean slate
212
  return ts_type;
213
}
214
215
/*
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
216
  Convert a time string to a DRIZZLE_TIME struct and produce a warning
1 by brian
clean slate
217
  if string was cut during conversion.
218
219
  NOTE
220
    See str_to_time() for more info.
221
*/
222
bool
482 by Brian Aker
Remove uint.
223
str_to_time_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time)
1 by brian
clean slate
224
{
225
  int warning;
226
  bool ret_val= str_to_time(str, length, l_time, &warning);
227
  if (ret_val || warning)
520.1.22 by Brian Aker
Second pass of thd cleanup
228
    make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
461 by Monty Taylor
Removed NullS. bu-bye.
229
                                 str, length, DRIZZLE_TIMESTAMP_TIME, NULL);
1 by brian
clean slate
230
  return ret_val;
231
}
232
233
234
/*
235
  Convert a system time structure to TIME
236
*/
237
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
238
void localtime_to_TIME(DRIZZLE_TIME *to, struct tm *from)
1 by brian
clean slate
239
{
240
  to->neg=0;
241
  to->second_part=0;
242
  to->year=	(int) ((from->tm_year+1900) % 10000);
243
  to->month=	(int) from->tm_mon+1;
244
  to->day=	(int) from->tm_mday;
245
  to->hour=	(int) from->tm_hour;
246
  to->minute=	(int) from->tm_min;
247
  to->second=   (int) from->tm_sec;
248
}
249
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
250
void calc_time_from_sec(DRIZZLE_TIME *to, long seconds, long microseconds)
1 by brian
clean slate
251
{
252
  long t_seconds;
253
  // 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.
254
  to->time_type= DRIZZLE_TIMESTAMP_TIME;
1 by brian
clean slate
255
  to->year= 0;
256
  to->month= 0;
257
  to->day= 0;
258
  to->hour= seconds/3600L;
259
  t_seconds= seconds%3600L;
260
  to->minute= t_seconds/60L;
261
  to->second= t_seconds%60L;
262
  to->second_part= microseconds;
263
}
264
907.1.2 by Jay Pipes
Merging in old r902 temporal changes
265
void make_time(const DRIZZLE_TIME *l_time, String *str)
266
{
910.4.7 by Stewart Smith
ensure there is enough space allocated to String for string representation of date/time types.
267
  str->alloc(MAX_DATE_STRING_REP_LENGTH);
268
  uint32_t length= (uint32_t) my_time_to_str(l_time, str->c_ptr());
907.1.2 by Jay Pipes
Merging in old r902 temporal changes
269
  str->length(length);
270
  str->set_charset(&my_charset_bin);
271
}
272
273
274
void make_date(const DRIZZLE_TIME *l_time, String *str)
275
{
910.4.7 by Stewart Smith
ensure there is enough space allocated to String for string representation of date/time types.
276
  str->alloc(MAX_DATE_STRING_REP_LENGTH);
277
  uint32_t length= (uint32_t) my_date_to_str(l_time, str->c_ptr());
907.1.2 by Jay Pipes
Merging in old r902 temporal changes
278
  str->length(length);
279
  str->set_charset(&my_charset_bin);
280
}
281
282
283
void make_datetime(const DRIZZLE_TIME *l_time, String *str)
284
{
910.4.7 by Stewart Smith
ensure there is enough space allocated to String for string representation of date/time types.
285
  str->alloc(MAX_DATE_STRING_REP_LENGTH);
286
  uint32_t length= (uint32_t) my_datetime_to_str(l_time, str->c_ptr());
1 by brian
clean slate
287
  str->length(length);
288
  str->set_charset(&my_charset_bin);
289
}
290
291
520.1.22 by Brian Aker
Second pass of thd cleanup
292
void make_truncated_value_warning(Session *session, DRIZZLE_ERROR::enum_warning_level level,
1 by brian
clean slate
293
                                  const char *str_val,
482 by Brian Aker
Remove uint.
294
				  uint32_t str_length,
398.1.1 by Monty Taylor
Remove typedef enum enum_drizzle_timestamp_type timestamp_type;
295
                                  enum enum_drizzle_timestamp_type time_type,
1 by brian
clean slate
296
                                  const char *field_name)
297
{
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
298
  char warn_buff[DRIZZLE_ERRMSG_SIZE];
1 by brian
clean slate
299
  const char *type_str;
383.1.12 by Brian Aker
Much closer toward UTF8 being around all the time...
300
  CHARSET_INFO *cs= &my_charset_utf8_general_ci;
1 by brian
clean slate
301
  char buff[128];
205 by Brian Aker
uint32 -> uin32_t
302
  String str(buff,(uint32_t) sizeof(buff), system_charset_info);
1 by brian
clean slate
303
  str.copy(str_val, str_length, system_charset_info);
304
  str[str_length]= 0;               // Ensure we have end 0 for snprintf
305
306
  switch (time_type) {
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
307
    case DRIZZLE_TIMESTAMP_DATE:
1 by brian
clean slate
308
      type_str= "date";
309
      break;
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
310
    case DRIZZLE_TIMESTAMP_TIME:
1 by brian
clean slate
311
      type_str= "time";
312
      break;
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
313
    case DRIZZLE_TIMESTAMP_DATETIME:  // FALLTHROUGH
1 by brian
clean slate
314
    default:
315
      type_str= "datetime";
316
      break;
317
  }
318
  if (field_name)
319
    cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
320
                       ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
321
                       type_str, str.c_ptr(), field_name,
520.1.22 by Brian Aker
Second pass of thd cleanup
322
                       (uint32_t) session->row_count);
1 by brian
clean slate
323
  else
324
  {
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
325
    if (time_type > DRIZZLE_TIMESTAMP_ERROR)
1 by brian
clean slate
326
      cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
327
                         ER(ER_TRUNCATED_WRONG_VALUE),
328
                         type_str, str.c_ptr());
329
    else
330
      cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
331
                         ER(ER_WRONG_VALUE), type_str, str.c_ptr());
332
  }
520.1.22 by Brian Aker
Second pass of thd cleanup
333
  push_warning(session, level,
1 by brian
clean slate
334
               ER_TRUNCATED_WRONG_VALUE, warn_buff);
335
}
336
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
337
bool date_add_interval(DRIZZLE_TIME *ltime, interval_type int_type, INTERVAL interval)
1 by brian
clean slate
338
{
339
  long period, sign;
340
341
  ltime->neg= 0;
342
343
  sign= (interval.neg ? -1 : 1);
344
345
  switch (int_type) {
346
  case INTERVAL_SECOND:
347
  case INTERVAL_SECOND_MICROSECOND:
348
  case INTERVAL_MICROSECOND:
349
  case INTERVAL_MINUTE:
350
  case INTERVAL_HOUR:
351
  case INTERVAL_MINUTE_MICROSECOND:
352
  case INTERVAL_MINUTE_SECOND:
353
  case INTERVAL_HOUR_MICROSECOND:
354
  case INTERVAL_HOUR_SECOND:
355
  case INTERVAL_HOUR_MINUTE:
356
  case INTERVAL_DAY_MICROSECOND:
357
  case INTERVAL_DAY_SECOND:
358
  case INTERVAL_DAY_MINUTE:
359
  case INTERVAL_DAY_HOUR:
360
  {
152 by Brian Aker
longlong replacement
361
    int64_t sec, days, daynr, microseconds, extra_sec;
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
362
    ltime->time_type= DRIZZLE_TIMESTAMP_DATETIME; // Return full date
1 by brian
clean slate
363
    microseconds= ltime->second_part + sign*interval.second_part;
364
    extra_sec= microseconds/1000000L;
365
    microseconds= microseconds%1000000L;
366
367
    sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
368
	 ltime->second +
152 by Brian Aker
longlong replacement
369
	 sign* (int64_t) (interval.day*3600*24L +
398.1.8 by Monty Taylor
Enabled -Wlong-long.
370
                           interval.hour*3600L+interval.minute*60L+
1 by brian
clean slate
371
                           interval.second))+ extra_sec;
372
    if (microseconds < 0)
373
    {
398.1.8 by Monty Taylor
Enabled -Wlong-long.
374
      microseconds+= 1000000L;
1 by brian
clean slate
375
      sec--;
376
    }
398.1.8 by Monty Taylor
Enabled -Wlong-long.
377
    days= sec/(3600*24L);
378
    sec-= days*3600*24L;
1 by brian
clean slate
379
    if (sec < 0)
380
    {
381
      days--;
398.1.8 by Monty Taylor
Enabled -Wlong-long.
382
      sec+= 3600*24L;
1 by brian
clean slate
383
    }
895 by Brian Aker
Completion (?) of uint conversion.
384
    ltime->second_part= (uint32_t) microseconds;
385
    ltime->second= (uint32_t) (sec % 60);
386
    ltime->minute= (uint32_t) (sec/60 % 60);
387
    ltime->hour=   (uint32_t) (sec/3600);
1 by brian
clean slate
388
    daynr= calc_daynr(ltime->year,ltime->month,1) + days;
389
    /* Day number from year 0 to 9999-12-31 */
151 by Brian Aker
Ulonglong to uint64_t
390
    if ((uint64_t) daynr > MAX_DAY_NUMBER)
1 by brian
clean slate
391
      goto invalid_date;
392
    get_date_from_daynr((long) daynr, &ltime->year, &ltime->month,
393
                        &ltime->day);
394
    break;
395
  }
396
  case INTERVAL_DAY:
397
  case INTERVAL_WEEK:
398
    period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
399
             sign * (long) interval.day);
400
    /* 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)
401
    if (period > MAX_DAY_NUMBER)
1 by brian
clean slate
402
      goto invalid_date;
403
    get_date_from_daynr((long) period,&ltime->year,&ltime->month,&ltime->day);
404
    break;
405
  case INTERVAL_YEAR:
406
    ltime->year+= sign * (long) interval.year;
520.1.7 by Brian Aker
More ulong fixes (including a bug on row return on error)
407
    if (ltime->year >= 10000L)
1 by brian
clean slate
408
      goto invalid_date;
409
    if (ltime->month == 2 && ltime->day == 29 &&
410
	calc_days_in_year(ltime->year) != 366)
411
      ltime->day=28;				// Was leap-year
412
    break;
413
  case INTERVAL_YEAR_MONTH:
414
  case INTERVAL_QUARTER:
415
  case INTERVAL_MONTH:
416
    period= (ltime->year*12 + sign * (long) interval.year*12 +
417
	     ltime->month-1 + sign * (long) interval.month);
520.1.7 by Brian Aker
More ulong fixes (including a bug on row return on error)
418
    if (period >= 120000L)
1 by brian
clean slate
419
      goto invalid_date;
895 by Brian Aker
Completion (?) of uint conversion.
420
    ltime->year= (uint32_t) (period / 12);
421
    ltime->month= (uint32_t) (period % 12L)+1;
1 by brian
clean slate
422
    /* Adjust day if the new month doesn't have enough days */
423
    if (ltime->day > days_in_month[ltime->month-1])
424
    {
425
      ltime->day = days_in_month[ltime->month-1];
426
      if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
427
	ltime->day++;				// Leap-year
428
    }
429
    break;
430
  default:
431
    goto null_date;
432
  }
433
434
  return 0;					// Ok
435
436
invalid_date:
520.1.22 by Brian Aker
Second pass of thd cleanup
437
  push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1 by brian
clean slate
438
                      ER_DATETIME_FUNCTION_OVERFLOW,
439
                      ER(ER_DATETIME_FUNCTION_OVERFLOW),
440
                      "datetime");
441
null_date:
442
  return 1;
443
}
444
445
446
/*
447
  Calculate difference between two datetime values as seconds + microseconds.
448
449
  SYNOPSIS
450
    calc_time_diff()
451
      l_time1         - TIME/DATE/DATETIME value
452
      l_time2         - TIME/DATE/DATETIME value
453
      l_sign          - 1 absolute values are substracted,
454
                        -1 absolute values are added.
455
      seconds_out     - Out parameter where difference between
456
                        l_time1 and l_time2 in seconds is stored.
457
      microseconds_out- Out parameter where microsecond part of difference
458
                        between l_time1 and l_time2 is stored.
459
460
  NOTE
461
    This function calculates difference between l_time1 and l_time2 absolute
462
    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.
463
    signs into account (i.e. for DRIZZLE_TIME values).
1 by brian
clean slate
464
465
  RETURN VALUES
466
    Returns sign of difference.
467
    1 means negative result
468
    0 means positive result
469
470
*/
471
472
bool
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
473
calc_time_diff(DRIZZLE_TIME *l_time1, DRIZZLE_TIME *l_time2, int l_sign, int64_t *seconds_out,
1 by brian
clean slate
474
               long *microseconds_out)
475
{
476
  long days;
477
  bool neg;
152 by Brian Aker
longlong replacement
478
  int64_t microseconds;
1 by brian
clean slate
479
480
  /*
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
481
    We suppose that if first argument is DRIZZLE_TIMESTAMP_TIME
1 by brian
clean slate
482
    the second argument should be TIMESTAMP_TIME also.
483
    We should check it before calc_time_diff call.
484
  */
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
485
  if (l_time1->time_type == DRIZZLE_TIMESTAMP_TIME)  // Time value
1 by brian
clean slate
486
    days= (long)l_time1->day - l_sign * (long)l_time2->day;
487
  else
488
  {
895 by Brian Aker
Completion (?) of uint conversion.
489
    days= calc_daynr((uint32_t) l_time1->year,
490
		     (uint32_t) l_time1->month,
491
		     (uint32_t) l_time1->day);
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
492
    if (l_time2->time_type == DRIZZLE_TIMESTAMP_TIME)
1 by brian
clean slate
493
      days-= l_sign * (long)l_time2->day;
494
    else
895 by Brian Aker
Completion (?) of uint conversion.
495
      days-= l_sign*calc_daynr((uint32_t) l_time2->year,
496
			       (uint32_t) l_time2->month,
497
			       (uint32_t) l_time2->day);
1 by brian
clean slate
498
  }
499
398.1.8 by Monty Taylor
Enabled -Wlong-long.
500
  microseconds= ((int64_t)days*86400L +
152 by Brian Aker
longlong replacement
501
                 (int64_t)(l_time1->hour*3600L +
1 by brian
clean slate
502
                            l_time1->minute*60L +
503
                            l_time1->second) -
152 by Brian Aker
longlong replacement
504
                 l_sign*(int64_t)(l_time2->hour*3600L +
1 by brian
clean slate
505
                                   l_time2->minute*60L +
398.1.8 by Monty Taylor
Enabled -Wlong-long.
506
                                   l_time2->second)) * 1000000L +
152 by Brian Aker
longlong replacement
507
                (int64_t)l_time1->second_part -
508
                l_sign*(int64_t)l_time2->second_part;
1 by brian
clean slate
509
510
  neg= 0;
511
  if (microseconds < 0)
512
  {
513
    microseconds= -microseconds;
514
    neg= 1;
515
  }
516
  *seconds_out= microseconds/1000000L;
517
  *microseconds_out= (long) (microseconds%1000000L);
518
  return neg;
519
}
520
521
522
/*
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
523
  Compares 2 DRIZZLE_TIME structures
1 by brian
clean slate
524
525
  SYNOPSIS
526
    my_time_compare()
527
528
      a - first time
529
      b - second time
530
531
  RETURN VALUE
532
   -1   - a < b
533
    0   - a == b
534
    1   - a > b
535
536
  NOTES
537
    TIME.second_part is not considered during comparison
538
*/
539
540
int
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
541
my_time_compare(DRIZZLE_TIME *a, DRIZZLE_TIME *b)
1 by brian
clean slate
542
{
157 by Brian Aker
Second pass cleanup on removal of my_uint types
543
  uint64_t a_t= TIME_to_uint64_t_datetime(a);
544
  uint64_t b_t= TIME_to_uint64_t_datetime(b);
1 by brian
clean slate
545
546
  if (a_t > b_t)
547
    return 1;
548
  else if (a_t < b_t)
549
    return -1;
550
551
  return 0;
552
}
553
554
#endif