~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/calendar.cc

  • Committer: Stewart Smith
  • Date: 2008-11-21 16:06:07 UTC
  • mto: This revision was merged to the branch mainline in revision 593.
  • Revision ID: stewart@flamingspork.com-20081121160607-n6gdlt013spuo54r
remove mysql_frm_type
and fix engines to return correct value from delete_table when table doesn't exist.
(it should be ENOENT).

Also fix up some tests that manipulated frm files by hand. These tests are no longer valid and will need to be rewritten in the not too distant future.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2008 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; either version 2 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  This program is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with this program; if not, write to the Free Software
18
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
 
 */
20
 
 
21
 
/**
22
 
 * @file 
23
 
 *
24
 
 * Common functions for dealing with calendrical calculations
25
 
 */
26
 
 
27
 
#include "config.h"
28
 
 
29
 
#if TIME_WITH_SYS_TIME
30
 
# include <sys/time.h>
31
 
# include <time.h>
32
 
#else
33
 
# if HAVE_SYS_TIME_H
34
 
#  include <sys/time.h>
35
 
# else
36
 
#  include <time.h>
37
 
# endif
38
 
#endif
39
 
#include <cstdlib>
40
 
 
41
 
#include "drizzled/calendar.h"
42
 
 
43
 
namespace drizzled
44
 
{
45
 
 
46
 
/** Static arrays for number of days in a month and their "day ends" */
47
 
static const uint32_t __leap_days_in_month[12]=       {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
48
 
static const uint32_t __normal_days_in_month[12]=     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
49
 
static const uint32_t __leap_days_to_end_month[13]=   {0, 31, 60, 91, 121, 151, 182, 213, 244, 274, 305, 335, 366};
50
 
static const uint32_t __normal_days_to_end_month[13]= {0, 31, 59, 90, 120, 150, 181, 212, 243, 273, 304, 334, 365};
51
 
 
52
 
/** 
53
 
 * Private utility macro for enabling a switch between
54
 
 * Gregorian and Julian leap year date arrays.
55
 
 */
56
 
#define __DAYS_IN_MONTH(y, c) (const uint32_t *) (IS_LEAP_YEAR((y),(c)) ? __leap_days_in_month : __normal_days_in_month)
57
 
#define __DAYS_TO_END_MONTH(y, c) (const uint32_t *) (IS_LEAP_YEAR((y),(c)) ? __leap_days_to_end_month : __normal_days_to_end_month)
58
 
 
59
 
 
60
 
/**
61
 
 * Calculates the Julian Day Number from the year, month 
62
 
 * and day supplied.  The calendar used by the supplied
63
 
 * year, month, and day is assumed to be Gregorian Proleptic.
64
 
 *
65
 
 * The months January to December are 1 to 12. 
66
 
 * Astronomical year numbering is used, thus 1 BC is 0, 2 BC is −1, 
67
 
 * and 4713 BC is −4712. In all divisions (except for JD) the floor 
68
 
 * function is applied to the quotient (for dates since 
69
 
 * March 1, −4800 all quotients are non-negative, so we can also 
70
 
 * apply truncation).
71
 
 *
72
 
 * a = (14 - month) / 12
73
 
 * y = year + 4800 - a
74
 
 * m = month + 12a - 3
75
 
 * JDN = day + ((153m + 2) / 5) + 365y + (y / 4) - (y / 100) + (y / 400) - 32045
76
 
 *
77
 
 * @cite http://en.wikipedia.org/wiki/Julian_day#Calculation
78
 
 *
79
 
 * @note
80
 
 *
81
 
 * Year month and day values are assumed to be valid.  This 
82
 
 * method does no bounds checking or validation.
83
 
 *
84
 
 * @param Year of date
85
 
 * @param Month of date
86
 
 * @param Day of date
87
 
 */
88
 
int64_t julian_day_number_from_gregorian_date(uint32_t year, uint32_t month, uint32_t day)
89
 
{
90
 
  int64_t day_number;
91
 
  int64_t a= (14 - month) / 12;
92
 
  int64_t y= year + 4800 - a;
93
 
  int64_t m= month + (12 * a) - 3;
94
 
 
95
 
  day_number= day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) - (y / 100) + (y / 400) - 32045;
96
 
  return day_number;
97
 
}
98
 
 
99
 
/**
100
 
 * Translates an absolute day number to a 
101
 
 * Julian day number.  Note that a Julian day number
102
 
 * is not the same as a date in the Julian proleptic calendar.
103
 
 *
104
 
 * @param The absolute day number
105
 
 */
106
 
int64_t absolute_day_number_to_julian_day_number(int64_t absolute_day)
107
 
{
108
 
  return absolute_day + JULIAN_DAY_NUMBER_AT_ABSOLUTE_DAY_ONE;
109
 
}
110
 
 
111
 
/**
112
 
 * Translates a Julian day number to an 
113
 
 * absolute day number.  Note that a Julian day number
114
 
 * is not the same as a date in the Julian proleptic calendar.
115
 
 *
116
 
 * @param The Julian day number
117
 
 */
118
 
int64_t julian_day_number_to_absolute_day_number(int64_t julian_day)
119
 
{
120
 
  return julian_day - JULIAN_DAY_NUMBER_AT_ABSOLUTE_DAY_ONE;
121
 
}
122
 
 
123
 
/**
124
 
 * Given a supplied Julian Day Number, populates a year, month, and day
125
 
 * with the date in the Gregorian Proleptic calendar which corresponds to
126
 
 * the given Julian Day Number.
127
 
 *
128
 
 * @cite Algorithm from http://en.wikipedia.org/wiki/Julian_day
129
 
 *
130
 
 * @param Julian Day Number
131
 
 * @param Pointer to year to populate
132
 
 * @param Pointer to month to populate
133
 
 * @param Pointer to the day to populate
134
 
 */
135
 
void gregorian_date_from_julian_day_number(int64_t julian_day
136
 
                                         , uint32_t *year_out
137
 
                                         , uint32_t *month_out
138
 
                                         , uint32_t *day_out)
139
 
{
140
 
  int64_t j = julian_day + 32044;
141
 
  int64_t g = j / 146097;
142
 
  int64_t dg = j % 146097;
143
 
  int64_t c = (dg / 36524 + 1) * 3 / 4;
144
 
  int64_t dc = dg - c * 36524;
145
 
  int64_t b = dc / 1461;
146
 
  int64_t db = dc % 1461;
147
 
  int64_t a = (db / 365 + 1) * 3 / 4;
148
 
  int64_t da = db - a * 365;
149
 
  int64_t y = g * 400 + c * 100 + b * 4 + a;
150
 
  int64_t m = (da * 5 + 308) / 153 - 2;
151
 
  int64_t d = da - (m + 4) * 153 / 5 + 122;
152
 
  int64_t Y = y - 4800 + (m + 2) / 12;
153
 
  int64_t M = (m + 2) % 12 + 1;
154
 
  int64_t D = (int64_t)((double)d + 1.5);
155
 
 
156
 
  /* Push out parameters */
157
 
  *year_out= (uint32_t) Y;
158
 
  *month_out= (uint32_t) M;
159
 
  *day_out= (uint32_t) D;
160
 
}
161
 
 
162
 
/**
163
 
 * Given a supplied Absolute Day Number, populates a year, month, and day
164
 
 * with the date in the Gregorian Proleptic calendar which corresponds to
165
 
 * the given Absolute Day Number.
166
 
 *
167
 
 * @param Absolute Day Number
168
 
 * @param Pointer to year to populate
169
 
 * @param Pointer to month to populate
170
 
 * @param Pointer to the day to populate
171
 
 */
172
 
void gregorian_date_from_absolute_day_number(int64_t absolute_day
173
 
                                           , uint32_t *year_out
174
 
                                           , uint32_t *month_out
175
 
                                           , uint32_t *day_out)
176
 
{
177
 
  gregorian_date_from_julian_day_number(
178
 
      absolute_day_number_to_julian_day_number(absolute_day)
179
 
    , year_out
180
 
    , month_out
181
 
    , day_out);
182
 
}
183
 
 
184
 
/**
185
 
 * Functions to calculate the number of days in a 
186
 
 * particular year.  The number of days in a year 
187
 
 * depends on the calendar used for the date.
188
 
 *
189
 
 * For the Julian proleptic calendar, a leap year 
190
 
 * is one which is evenly divisible by 4.
191
 
 *
192
 
 * For the Gregorian proleptic calendar, a leap year
193
 
 * is one which is evenly divisible by 4, and if
194
 
 * the year is evenly divisible by 100, it must also be evenly
195
 
 * divisible by 400.
196
 
 */
197
 
 
198
 
/**
199
 
 * Returns the number of days in a particular year
200
 
 * depending on the supplied calendar.
201
 
 *
202
 
 * @param year to evaluate
203
 
 * @param calendar to use
204
 
 */
205
 
inline uint32_t days_in_year(const uint32_t year, enum calendar calendar)
206
 
{
207
 
  if (calendar == GREGORIAN)
208
 
    return days_in_year_gregorian(year);
209
 
  return days_in_year_julian(year);
210
 
}
211
 
 
212
 
/**
213
 
 * Returns the number of days in a particular Julian calendar year.
214
 
 *
215
 
 * @param year to evaluate
216
 
 */
217
 
inline uint32_t days_in_year_julian(const uint32_t year)
218
 
{
219
 
  /* Short-circuit. No odd years can be leap years... */
220
 
  return (year & 3) == 0;
221
 
}
222
 
 
223
 
/**
224
 
 * Returns the number of days in a particular Gregorian year.
225
 
 *
226
 
 * @param year to evaluate
227
 
 */
228
 
inline uint32_t days_in_year_gregorian(const uint32_t year)
229
 
{
230
 
  /* Short-circuit. No odd years can be leap years... */
231
 
  if ((year & 1) == 1)
232
 
    return 365;
233
 
  return (            
234
 
            (year & 3) == 0 
235
 
            && (year % 100 || ((year % 400 == 0) && year)) 
236
 
            ? 366 
237
 
            : 365
238
 
         );
239
 
}
240
 
 
241
 
/**
242
 
 * Returns the number of the day in a week.
243
 
 *
244
 
 * Return values:
245
 
 *
246
 
 * Day            Day Number  Sunday first day?
247
 
 * -------------- ----------- -----------------
248
 
 * Sunday         0           true
249
 
 * Monday         1           true
250
 
 * Tuesday        2           true
251
 
 * Wednesday      3           true
252
 
 * Thursday       4           true
253
 
 * Friday         5           true
254
 
 * Saturday       6           true
255
 
 * Sunday         6           false
256
 
 * Monday         0           false
257
 
 * Tuesday        1           false
258
 
 * Wednesday      2           false
259
 
 * Thursday       3           false
260
 
 * Friday         4           false
261
 
 * Saturday       5           false
262
 
 *
263
 
 * @param Julian Day Number
264
 
 * @param Consider Sunday the first day of the week?
265
 
 */
266
 
uint32_t day_of_week(int64_t day_number
267
 
                   , bool sunday_is_first_day_of_week)
268
 
{
269
 
  uint32_t tmp= (uint32_t) (day_number % 7);
270
 
  /* 0 returned from above modulo is a Monday */
271
 
  if (sunday_is_first_day_of_week)
272
 
    tmp= (tmp == 6 ? 0 : tmp + 1);
273
 
  return tmp;
274
 
}
275
 
 
276
 
/**
277
 
 * Given a year, month, and day, returns whether the date is 
278
 
 * valid for the Gregorian proleptic calendar.
279
 
 *
280
 
 * @param The year
281
 
 * @param The month
282
 
 * @param The day
283
 
 */
284
 
bool is_valid_gregorian_date(uint32_t year, uint32_t month, uint32_t day)
285
 
{
286
 
  if (year < 1)
287
 
    return false;
288
 
  if (month != 2)
289
 
    return (day <= __normal_days_in_month[month - 1]);
290
 
  else
291
 
  {
292
 
    const uint32_t *p_months= __DAYS_IN_MONTH(year, (enum calendar) GREGORIAN);
293
 
    return (day <= p_months[1]);
294
 
  }
295
 
}
296
 
 
297
 
/**
298
 
 * Returns the number of days in a month, given
299
 
 * a year and a month in the Gregorian calendar.
300
 
 *
301
 
 * @param Year in Gregorian Proleptic calendar
302
 
 * @param Month in date
303
 
 */
304
 
uint32_t days_in_gregorian_year_month(uint32_t year, uint32_t month)
305
 
{
306
 
  const uint32_t *p_months= __DAYS_IN_MONTH(year, GREGORIAN);
307
 
  return p_months[month - 1];
308
 
}
309
 
 
310
 
/**
311
 
 * Returns whether the supplied date components are within the 
312
 
 * range of the UNIX epoch.
313
 
 *
314
 
 * Times in the range of 1970-01-01T00:00:00 to 2038-01-19T03:14:07
315
 
 *
316
 
 * @param Year
317
 
 * @param Month
318
 
 * @param Day
319
 
 * @param Hour
320
 
 * @param Minute
321
 
 * @param Second
322
 
 */
323
 
bool in_unix_epoch_range(uint32_t year
324
 
                       , uint32_t month
325
 
                       , uint32_t day
326
 
                       , uint32_t hour
327
 
                       , uint32_t minute
328
 
                       , uint32_t second)
329
 
{
330
 
  if (month == 0 || day == 0)
331
 
    return false;
332
 
  if (year < UNIX_EPOCH_MAX_YEARS
333
 
      && year >= UNIX_EPOCH_MIN_YEARS)
334
 
    return true;
335
 
  if (year < UNIX_EPOCH_MIN_YEARS)
336
 
    return false;
337
 
  if (year == UNIX_EPOCH_MAX_YEARS)
338
 
  {
339
 
    if (month > 1)
340
 
      return false;
341
 
    if (day > 19)
342
 
      return false;
343
 
    else if (day < 19)
344
 
      return true;
345
 
    else
346
 
    {
347
 
      /* We are on the final day of UNIX Epoch */
348
 
      uint32_t seconds= (hour * 60 * 60)
349
 
                      + (minute * 60)
350
 
                      + (second);
351
 
      if (seconds <= ((3 * 60 * 60) + (14 * 60) + 7))
352
 
        return true;
353
 
      return false;
354
 
    }
355
 
  }
356
 
  return false;
357
 
}
358
 
 
359
 
/**
360
 
 * Returns the number of the week from a supplied year, month, and
361
 
 * date in the Gregorian proleptic calendar.  We use strftime() and
362
 
 * the %U, %W, and %V format specifiers depending on the value
363
 
 * of the sunday_is_first_day_of_week parameter.
364
 
 *
365
 
 * @param Subject year
366
 
 * @param Subject month
367
 
 * @param Subject day
368
 
 * @param Is sunday the first day of the week?
369
 
 * @param Pointer to a uint32_t to hold the resulting year, which 
370
 
 *        may be incremented or decremented depending on flags
371
 
 */
372
 
uint32_t week_number_from_gregorian_date(uint32_t year
373
 
                                       , uint32_t month
374
 
                                       , uint32_t day
375
 
                                       , bool sunday_is_first_day_of_week)
376
 
{
377
 
  struct tm broken_time;
378
 
 
379
 
  broken_time.tm_year= year;
380
 
  broken_time.tm_mon= month - 1; /* struct tm has non-ordinal months */
381
 
  broken_time.tm_mday= day;
382
 
 
383
 
  /* fill out the rest of our tm fields. */
384
 
  (void) mktime(&broken_time);
385
 
 
386
 
  char result[3]; /* 3 is enough space for a max 2-digit week number */
387
 
  size_t result_len= strftime(result
388
 
                            , sizeof(result)
389
 
                            , (sunday_is_first_day_of_week ? "%U" : "%W")
390
 
                            , &broken_time);
391
 
 
392
 
  if (result_len != 0)
393
 
    return (uint32_t) atoi(result);
394
 
  return 0;
395
 
}
396
 
 
397
 
/**
398
 
 * Returns the ISO week number of a supplied year, month, and
399
 
 * date in the Gregorian proleptic calendar.  We use strftime() and
400
 
 * the %V format specifier to do the calculation, which yields a
401
 
 * correct ISO 8601:1988 week number.
402
 
 *
403
 
 * The final year_out parameter is a pointer to an integer which will
404
 
 * be set to the year in which the week belongs, according to ISO8601:1988, 
405
 
 * which may be different from the Gregorian calendar year.
406
 
 *
407
 
 * @see http://en.wikipedia.org/wiki/ISO_8601
408
 
 *
409
 
 * @param Subject year
410
 
 * @param Subject month
411
 
 * @param Subject day
412
 
 * @param Pointer to a uint32_t to hold the resulting year, which 
413
 
 *        may be incremented or decremented depending on flags
414
 
 */
415
 
uint32_t iso_week_number_from_gregorian_date(uint32_t year
416
 
                                           , uint32_t month
417
 
                                           , uint32_t day
418
 
                                           , uint32_t *year_out)
419
 
{
420
 
  struct tm broken_time;
421
 
 
422
 
  if (year_out != NULL)
423
 
    *year_out= year;
424
 
 
425
 
  broken_time.tm_year= year;
426
 
  broken_time.tm_mon= month - 1; /* struct tm has non-ordinal months */
427
 
  broken_time.tm_mday= day;
428
 
 
429
 
  /* fill out the rest of our tm fields. */
430
 
  (void) mktime(&broken_time);
431
 
 
432
 
  char result[3]; /* 3 is enough space for a max 2-digit week number */
433
 
  size_t result_len= strftime(result
434
 
                            , sizeof(result)
435
 
                            , "%V"
436
 
                            , &broken_time);
437
 
 
438
 
 
439
 
  if (result_len == 0)
440
 
    return 0; /* Not valid for ISO8601:1988 */
441
 
 
442
 
  uint32_t week_number= (uint32_t) atoi(result);
443
 
 
444
 
  /* 
445
 
   * ISO8601:1988 states that if the first week in January
446
 
   * does not contain 4 days, then the resulting week number
447
 
   * shall be 52 or 53, depending on the number of days in the
448
 
   * previous year.  In this case, we adjust the outbound
449
 
   * year parameter down a year.
450
 
   */
451
 
  if (year_out != NULL)
452
 
    if (week_number == 53 || week_number == 52)
453
 
      if (month == 1)
454
 
        *year_out--;
455
 
 
456
 
  return week_number;
457
 
}
458
 
 
459
 
/**
460
 
 * Takes a number in the form [YY]YYMM and converts it into
461
 
 * a number of months.
462
 
 *
463
 
 * @param Period in the form [YY]YYMM
464
 
 */
465
 
uint32_t year_month_to_months(uint32_t year_month)
466
 
{
467
 
  if (year_month == 0)
468
 
    return 0L;
469
 
 
470
 
  uint32_t years= year_month / 100;
471
 
  if (years < CALENDAR_YY_PART_YEAR)
472
 
    years+= 2000;
473
 
  else if (years < 100)
474
 
    years+= 1900;
475
 
 
476
 
  uint32_t months= year_month % 100;
477
 
  return (years * 12) + (months - 1);
478
 
}
479
 
 
480
 
/**
481
 
 * Takes a number of months and converts it to
482
 
 * a period in the form YYYYMM.
483
 
 *
484
 
 * @param Number of months
485
 
 */
486
 
uint32_t months_to_year_month(uint32_t months)
487
 
{
488
 
  if (months == 0L)
489
 
    return 0L;
490
 
 
491
 
  uint32_t years= (months / 12);
492
 
 
493
 
  if (years < 100)
494
 
    years+= (years < CALENDAR_YY_PART_YEAR) ? 2000 : 1900;
495
 
 
496
 
  return (years * 100) + (months % 12) + 1;
497
 
}
498
 
 
499
 
} /* namespace drizzled */