~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
337
/*
338
  Calculate difference between two datetime values as seconds + microseconds.
339
340
  SYNOPSIS
341
    calc_time_diff()
342
      l_time1         - TIME/DATE/DATETIME value
343
      l_time2         - TIME/DATE/DATETIME value
344
      l_sign          - 1 absolute values are substracted,
345
                        -1 absolute values are added.
346
      seconds_out     - Out parameter where difference between
347
                        l_time1 and l_time2 in seconds is stored.
348
      microseconds_out- Out parameter where microsecond part of difference
349
                        between l_time1 and l_time2 is stored.
350
351
  NOTE
352
    This function calculates difference between l_time1 and l_time2 absolute
353
    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.
354
    signs into account (i.e. for DRIZZLE_TIME values).
1 by brian
clean slate
355
356
  RETURN VALUES
357
    Returns sign of difference.
358
    1 means negative result
359
    0 means positive result
360
361
*/
362
363
bool
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
364
calc_time_diff(DRIZZLE_TIME *l_time1, DRIZZLE_TIME *l_time2, int l_sign, int64_t *seconds_out,
1 by brian
clean slate
365
               long *microseconds_out)
366
{
367
  long days;
368
  bool neg;
152 by Brian Aker
longlong replacement
369
  int64_t microseconds;
1 by brian
clean slate
370
371
  /*
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
372
    We suppose that if first argument is DRIZZLE_TIMESTAMP_TIME
1 by brian
clean slate
373
    the second argument should be TIMESTAMP_TIME also.
374
    We should check it before calc_time_diff call.
375
  */
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
376
  if (l_time1->time_type == DRIZZLE_TIMESTAMP_TIME)  // Time value
1 by brian
clean slate
377
    days= (long)l_time1->day - l_sign * (long)l_time2->day;
378
  else
379
  {
895 by Brian Aker
Completion (?) of uint conversion.
380
    days= calc_daynr((uint32_t) l_time1->year,
381
		     (uint32_t) l_time1->month,
382
		     (uint32_t) l_time1->day);
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
383
    if (l_time2->time_type == DRIZZLE_TIMESTAMP_TIME)
1 by brian
clean slate
384
      days-= l_sign * (long)l_time2->day;
385
    else
895 by Brian Aker
Completion (?) of uint conversion.
386
      days-= l_sign*calc_daynr((uint32_t) l_time2->year,
387
			       (uint32_t) l_time2->month,
388
			       (uint32_t) l_time2->day);
1 by brian
clean slate
389
  }
390
398.1.8 by Monty Taylor
Enabled -Wlong-long.
391
  microseconds= ((int64_t)days*86400L +
152 by Brian Aker
longlong replacement
392
                 (int64_t)(l_time1->hour*3600L +
1 by brian
clean slate
393
                            l_time1->minute*60L +
394
                            l_time1->second) -
152 by Brian Aker
longlong replacement
395
                 l_sign*(int64_t)(l_time2->hour*3600L +
1 by brian
clean slate
396
                                   l_time2->minute*60L +
398.1.8 by Monty Taylor
Enabled -Wlong-long.
397
                                   l_time2->second)) * 1000000L +
152 by Brian Aker
longlong replacement
398
                (int64_t)l_time1->second_part -
399
                l_sign*(int64_t)l_time2->second_part;
1 by brian
clean slate
400
401
  neg= 0;
402
  if (microseconds < 0)
403
  {
404
    microseconds= -microseconds;
405
    neg= 1;
406
  }
407
  *seconds_out= microseconds/1000000L;
408
  *microseconds_out= (long) (microseconds%1000000L);
409
  return neg;
410
}
411
412
413
/*
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
414
  Compares 2 DRIZZLE_TIME structures
1 by brian
clean slate
415
416
  SYNOPSIS
417
    my_time_compare()
418
419
      a - first time
420
      b - second time
421
422
  RETURN VALUE
423
   -1   - a < b
424
    0   - a == b
425
    1   - a > b
426
427
  NOTES
428
    TIME.second_part is not considered during comparison
429
*/
430
431
int
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
432
my_time_compare(DRIZZLE_TIME *a, DRIZZLE_TIME *b)
1 by brian
clean slate
433
{
157 by Brian Aker
Second pass cleanup on removal of my_uint types
434
  uint64_t a_t= TIME_to_uint64_t_datetime(a);
435
  uint64_t b_t= TIME_to_uint64_t_datetime(b);
1 by brian
clean slate
436
437
  if (a_t > b_t)
438
    return 1;
439
  else if (a_t < b_t)
440
    return -1;
441
442
  return 0;
443
}
444
445
#endif