~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
216
/*
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
217
  Convert a datetime from broken-down DRIZZLE_TIME representation to corresponding
1 by brian
clean slate
218
  TIMESTAMP value.
219
220
  SYNOPSIS
221
    TIME_to_timestamp()
520.1.22 by Brian Aker
Second pass of thd cleanup
222
      session             - current thread
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
223
      t               - datetime in broken-down representation,
1 by brian
clean slate
224
      in_dst_time_gap - pointer to bool which is set to true if t represents
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
225
                        value which doesn't exists (falls into the spring
1 by brian
clean slate
226
                        time-gap) or to false otherwise.
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
227
1 by brian
clean slate
228
  RETURN
229
     Number seconds in UTC since start of Unix Epoch corresponding to t.
230
     0 - t contains datetime value which is out of TIMESTAMP range.
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
231
1 by brian
clean slate
232
*/
726.1.1 by Toru Maesaka
Use time_t instead of my_time_t which should be safe (as in wide enough) on POSIX compliant systems.
233
time_t TIME_to_timestamp(Session *session, const DRIZZLE_TIME *t,
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.
234
                            bool *in_dst_time_gap)
1 by brian
clean slate
235
{
726.1.1 by Toru Maesaka
Use time_t instead of my_time_t which should be safe (as in wide enough) on POSIX compliant systems.
236
  time_t timestamp;
1 by brian
clean slate
237
238
  *in_dst_time_gap= 0;
239
520.1.22 by Brian Aker
Second pass of thd cleanup
240
  timestamp= session->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap);
1 by brian
clean slate
241
  if (timestamp)
242
  {
243
    return timestamp;
244
  }
245
246
  /* If we are here we have range error. */
247
  return(0);
248
}
249
250
251
/*
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
252
  Convert a time string to a DRIZZLE_TIME struct and produce a warning
1 by brian
clean slate
253
  if string was cut during conversion.
254
255
  NOTE
256
    See str_to_time() for more info.
257
*/
258
bool
482 by Brian Aker
Remove uint.
259
str_to_time_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time)
1 by brian
clean slate
260
{
261
  int warning;
262
  bool ret_val= str_to_time(str, length, l_time, &warning);
263
  if (ret_val || warning)
520.1.22 by Brian Aker
Second pass of thd cleanup
264
    make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
461 by Monty Taylor
Removed NullS. bu-bye.
265
                                 str, length, DRIZZLE_TIMESTAMP_TIME, NULL);
1 by brian
clean slate
266
  return ret_val;
267
}
268
269
270
/*
271
  Convert a system time structure to TIME
272
*/
273
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
274
void localtime_to_TIME(DRIZZLE_TIME *to, struct tm *from)
1 by brian
clean slate
275
{
276
  to->neg=0;
277
  to->second_part=0;
278
  to->year=	(int) ((from->tm_year+1900) % 10000);
279
  to->month=	(int) from->tm_mon+1;
280
  to->day=	(int) from->tm_mday;
281
  to->hour=	(int) from->tm_hour;
282
  to->minute=	(int) from->tm_min;
283
  to->second=   (int) from->tm_sec;
284
}
285
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
286
void calc_time_from_sec(DRIZZLE_TIME *to, long seconds, long microseconds)
1 by brian
clean slate
287
{
288
  long t_seconds;
289
  // 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.
290
  to->time_type= DRIZZLE_TIMESTAMP_TIME;
1 by brian
clean slate
291
  to->year= 0;
292
  to->month= 0;
293
  to->day= 0;
294
  to->hour= seconds/3600L;
295
  t_seconds= seconds%3600L;
296
  to->minute= t_seconds/60L;
297
  to->second= t_seconds%60L;
298
  to->second_part= microseconds;
299
}
300
907.1.2 by Jay Pipes
Merging in old r902 temporal changes
301
void make_time(const DRIZZLE_TIME *l_time, String *str)
302
{
303
  uint32_t length= (uint32_t) my_time_to_str(l_time, (char*) str->c_ptr());
304
  str->length(length);
305
  str->set_charset(&my_charset_bin);
306
}
307
308
309
void make_date(const DRIZZLE_TIME *l_time, String *str)
310
{
311
  uint32_t length= (uint32_t) my_date_to_str(l_time, (char*) str->c_ptr());
312
  str->length(length);
313
  str->set_charset(&my_charset_bin);
314
}
315
316
317
void make_datetime(const DRIZZLE_TIME *l_time, String *str)
318
{
319
  uint32_t length= (uint32_t) my_datetime_to_str(l_time, (char*) str->c_ptr());
1 by brian
clean slate
320
  str->length(length);
321
  str->set_charset(&my_charset_bin);
322
}
323
324
520.1.22 by Brian Aker
Second pass of thd cleanup
325
void make_truncated_value_warning(Session *session, DRIZZLE_ERROR::enum_warning_level level,
1 by brian
clean slate
326
                                  const char *str_val,
482 by Brian Aker
Remove uint.
327
				  uint32_t str_length,
398.1.1 by Monty Taylor
Remove typedef enum enum_drizzle_timestamp_type timestamp_type;
328
                                  enum enum_drizzle_timestamp_type time_type,
1 by brian
clean slate
329
                                  const char *field_name)
330
{
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
331
  char warn_buff[DRIZZLE_ERRMSG_SIZE];
1 by brian
clean slate
332
  const char *type_str;
383.1.12 by Brian Aker
Much closer toward UTF8 being around all the time...
333
  CHARSET_INFO *cs= &my_charset_utf8_general_ci;
1 by brian
clean slate
334
  char buff[128];
205 by Brian Aker
uint32 -> uin32_t
335
  String str(buff,(uint32_t) sizeof(buff), system_charset_info);
1 by brian
clean slate
336
  str.copy(str_val, str_length, system_charset_info);
337
  str[str_length]= 0;               // Ensure we have end 0 for snprintf
338
339
  switch (time_type) {
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
340
    case DRIZZLE_TIMESTAMP_DATE:
1 by brian
clean slate
341
      type_str= "date";
342
      break;
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
343
    case DRIZZLE_TIMESTAMP_TIME:
1 by brian
clean slate
344
      type_str= "time";
345
      break;
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
346
    case DRIZZLE_TIMESTAMP_DATETIME:  // FALLTHROUGH
1 by brian
clean slate
347
    default:
348
      type_str= "datetime";
349
      break;
350
  }
351
  if (field_name)
352
    cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
353
                       ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
354
                       type_str, str.c_ptr(), field_name,
520.1.22 by Brian Aker
Second pass of thd cleanup
355
                       (uint32_t) session->row_count);
1 by brian
clean slate
356
  else
357
  {
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
358
    if (time_type > DRIZZLE_TIMESTAMP_ERROR)
1 by brian
clean slate
359
      cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
360
                         ER(ER_TRUNCATED_WRONG_VALUE),
361
                         type_str, str.c_ptr());
362
    else
363
      cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
364
                         ER(ER_WRONG_VALUE), type_str, str.c_ptr());
365
  }
520.1.22 by Brian Aker
Second pass of thd cleanup
366
  push_warning(session, level,
1 by brian
clean slate
367
               ER_TRUNCATED_WRONG_VALUE, warn_buff);
368
}
369
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
370
bool date_add_interval(DRIZZLE_TIME *ltime, interval_type int_type, INTERVAL interval)
1 by brian
clean slate
371
{
372
  long period, sign;
373
374
  ltime->neg= 0;
375
376
  sign= (interval.neg ? -1 : 1);
377
378
  switch (int_type) {
379
  case INTERVAL_SECOND:
380
  case INTERVAL_SECOND_MICROSECOND:
381
  case INTERVAL_MICROSECOND:
382
  case INTERVAL_MINUTE:
383
  case INTERVAL_HOUR:
384
  case INTERVAL_MINUTE_MICROSECOND:
385
  case INTERVAL_MINUTE_SECOND:
386
  case INTERVAL_HOUR_MICROSECOND:
387
  case INTERVAL_HOUR_SECOND:
388
  case INTERVAL_HOUR_MINUTE:
389
  case INTERVAL_DAY_MICROSECOND:
390
  case INTERVAL_DAY_SECOND:
391
  case INTERVAL_DAY_MINUTE:
392
  case INTERVAL_DAY_HOUR:
393
  {
152 by Brian Aker
longlong replacement
394
    int64_t sec, days, daynr, microseconds, extra_sec;
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
395
    ltime->time_type= DRIZZLE_TIMESTAMP_DATETIME; // Return full date
1 by brian
clean slate
396
    microseconds= ltime->second_part + sign*interval.second_part;
397
    extra_sec= microseconds/1000000L;
398
    microseconds= microseconds%1000000L;
399
400
    sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
401
	 ltime->second +
152 by Brian Aker
longlong replacement
402
	 sign* (int64_t) (interval.day*3600*24L +
398.1.8 by Monty Taylor
Enabled -Wlong-long.
403
                           interval.hour*3600L+interval.minute*60L+
1 by brian
clean slate
404
                           interval.second))+ extra_sec;
405
    if (microseconds < 0)
406
    {
398.1.8 by Monty Taylor
Enabled -Wlong-long.
407
      microseconds+= 1000000L;
1 by brian
clean slate
408
      sec--;
409
    }
398.1.8 by Monty Taylor
Enabled -Wlong-long.
410
    days= sec/(3600*24L);
411
    sec-= days*3600*24L;
1 by brian
clean slate
412
    if (sec < 0)
413
    {
414
      days--;
398.1.8 by Monty Taylor
Enabled -Wlong-long.
415
      sec+= 3600*24L;
1 by brian
clean slate
416
    }
895 by Brian Aker
Completion (?) of uint conversion.
417
    ltime->second_part= (uint32_t) microseconds;
418
    ltime->second= (uint32_t) (sec % 60);
419
    ltime->minute= (uint32_t) (sec/60 % 60);
420
    ltime->hour=   (uint32_t) (sec/3600);
1 by brian
clean slate
421
    daynr= calc_daynr(ltime->year,ltime->month,1) + days;
422
    /* Day number from year 0 to 9999-12-31 */
151 by Brian Aker
Ulonglong to uint64_t
423
    if ((uint64_t) daynr > MAX_DAY_NUMBER)
1 by brian
clean slate
424
      goto invalid_date;
425
    get_date_from_daynr((long) daynr, &ltime->year, &ltime->month,
426
                        &ltime->day);
427
    break;
428
  }
429
  case INTERVAL_DAY:
430
  case INTERVAL_WEEK:
431
    period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
432
             sign * (long) interval.day);
433
    /* 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)
434
    if (period > MAX_DAY_NUMBER)
1 by brian
clean slate
435
      goto invalid_date;
436
    get_date_from_daynr((long) period,&ltime->year,&ltime->month,&ltime->day);
437
    break;
438
  case INTERVAL_YEAR:
439
    ltime->year+= sign * (long) interval.year;
520.1.7 by Brian Aker
More ulong fixes (including a bug on row return on error)
440
    if (ltime->year >= 10000L)
1 by brian
clean slate
441
      goto invalid_date;
442
    if (ltime->month == 2 && ltime->day == 29 &&
443
	calc_days_in_year(ltime->year) != 366)
444
      ltime->day=28;				// Was leap-year
445
    break;
446
  case INTERVAL_YEAR_MONTH:
447
  case INTERVAL_QUARTER:
448
  case INTERVAL_MONTH:
449
    period= (ltime->year*12 + sign * (long) interval.year*12 +
450
	     ltime->month-1 + sign * (long) interval.month);
520.1.7 by Brian Aker
More ulong fixes (including a bug on row return on error)
451
    if (period >= 120000L)
1 by brian
clean slate
452
      goto invalid_date;
895 by Brian Aker
Completion (?) of uint conversion.
453
    ltime->year= (uint32_t) (period / 12);
454
    ltime->month= (uint32_t) (period % 12L)+1;
1 by brian
clean slate
455
    /* Adjust day if the new month doesn't have enough days */
456
    if (ltime->day > days_in_month[ltime->month-1])
457
    {
458
      ltime->day = days_in_month[ltime->month-1];
459
      if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
460
	ltime->day++;				// Leap-year
461
    }
462
    break;
463
  default:
464
    goto null_date;
465
  }
466
467
  return 0;					// Ok
468
469
invalid_date:
520.1.22 by Brian Aker
Second pass of thd cleanup
470
  push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1 by brian
clean slate
471
                      ER_DATETIME_FUNCTION_OVERFLOW,
472
                      ER(ER_DATETIME_FUNCTION_OVERFLOW),
473
                      "datetime");
474
null_date:
475
  return 1;
476
}
477
478
479
/*
480
  Calculate difference between two datetime values as seconds + microseconds.
481
482
  SYNOPSIS
483
    calc_time_diff()
484
      l_time1         - TIME/DATE/DATETIME value
485
      l_time2         - TIME/DATE/DATETIME value
486
      l_sign          - 1 absolute values are substracted,
487
                        -1 absolute values are added.
488
      seconds_out     - Out parameter where difference between
489
                        l_time1 and l_time2 in seconds is stored.
490
      microseconds_out- Out parameter where microsecond part of difference
491
                        between l_time1 and l_time2 is stored.
492
493
  NOTE
494
    This function calculates difference between l_time1 and l_time2 absolute
495
    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.
496
    signs into account (i.e. for DRIZZLE_TIME values).
1 by brian
clean slate
497
498
  RETURN VALUES
499
    Returns sign of difference.
500
    1 means negative result
501
    0 means positive result
502
503
*/
504
505
bool
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
506
calc_time_diff(DRIZZLE_TIME *l_time1, DRIZZLE_TIME *l_time2, int l_sign, int64_t *seconds_out,
1 by brian
clean slate
507
               long *microseconds_out)
508
{
509
  long days;
510
  bool neg;
152 by Brian Aker
longlong replacement
511
  int64_t microseconds;
1 by brian
clean slate
512
513
  /*
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
514
    We suppose that if first argument is DRIZZLE_TIMESTAMP_TIME
1 by brian
clean slate
515
    the second argument should be TIMESTAMP_TIME also.
516
    We should check it before calc_time_diff call.
517
  */
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
518
  if (l_time1->time_type == DRIZZLE_TIMESTAMP_TIME)  // Time value
1 by brian
clean slate
519
    days= (long)l_time1->day - l_sign * (long)l_time2->day;
520
  else
521
  {
895 by Brian Aker
Completion (?) of uint conversion.
522
    days= calc_daynr((uint32_t) l_time1->year,
523
		     (uint32_t) l_time1->month,
524
		     (uint32_t) l_time1->day);
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
525
    if (l_time2->time_type == DRIZZLE_TIMESTAMP_TIME)
1 by brian
clean slate
526
      days-= l_sign * (long)l_time2->day;
527
    else
895 by Brian Aker
Completion (?) of uint conversion.
528
      days-= l_sign*calc_daynr((uint32_t) l_time2->year,
529
			       (uint32_t) l_time2->month,
530
			       (uint32_t) l_time2->day);
1 by brian
clean slate
531
  }
532
398.1.8 by Monty Taylor
Enabled -Wlong-long.
533
  microseconds= ((int64_t)days*86400L +
152 by Brian Aker
longlong replacement
534
                 (int64_t)(l_time1->hour*3600L +
1 by brian
clean slate
535
                            l_time1->minute*60L +
536
                            l_time1->second) -
152 by Brian Aker
longlong replacement
537
                 l_sign*(int64_t)(l_time2->hour*3600L +
1 by brian
clean slate
538
                                   l_time2->minute*60L +
398.1.8 by Monty Taylor
Enabled -Wlong-long.
539
                                   l_time2->second)) * 1000000L +
152 by Brian Aker
longlong replacement
540
                (int64_t)l_time1->second_part -
541
                l_sign*(int64_t)l_time2->second_part;
1 by brian
clean slate
542
543
  neg= 0;
544
  if (microseconds < 0)
545
  {
546
    microseconds= -microseconds;
547
    neg= 1;
548
  }
549
  *seconds_out= microseconds/1000000L;
550
  *microseconds_out= (long) (microseconds%1000000L);
551
  return neg;
552
}
553
554
555
/*
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
556
  Compares 2 DRIZZLE_TIME structures
1 by brian
clean slate
557
558
  SYNOPSIS
559
    my_time_compare()
560
561
      a - first time
562
      b - second time
563
564
  RETURN VALUE
565
   -1   - a < b
566
    0   - a == b
567
    1   - a > b
568
569
  NOTES
570
    TIME.second_part is not considered during comparison
571
*/
572
573
int
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
574
my_time_compare(DRIZZLE_TIME *a, DRIZZLE_TIME *b)
1 by brian
clean slate
575
{
157 by Brian Aker
Second pass cleanup on removal of my_uint types
576
  uint64_t a_t= TIME_to_uint64_t_datetime(a);
577
  uint64_t b_t= TIME_to_uint64_t_datetime(b);
1 by brian
clean slate
578
579
  if (a_t > b_t)
580
    return 1;
581
  else if (a_t < b_t)
582
    return -1;
583
584
  return 0;
585
}
586
587
#endif