~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/temporal_format.cc

Merged in latest plugin-slot-reorg.

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
 *  Authors:
 
7
 *
 
8
 *  Jay Pipes <jay.pipes@sun.com>
 
9
 *
 
10
 *  This program is free software; you can redistribute it and/or modify
 
11
 *  it under the terms of the GNU General Public License as published by
 
12
 *  the Free Software Foundation; either version 2 of the License, or
 
13
 *  (at your option) any later version.
 
14
 *
 
15
 *  This program is distributed in the hope that it will be useful,
 
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 *  GNU General Public License for more details.
 
19
 *
 
20
 *  You should have received a copy of the GNU General Public License
 
21
 *  along with this program; if not, write to the Free Software
 
22
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
23
 */
 
24
 
 
25
/**
 
26
 * @file 
 
27
 *
 
28
 * Implementation of the server's date and time string matching utility.
 
29
 */
 
30
 
 
31
#include "drizzled/global.h"
 
32
 
 
33
#include "drizzled/temporal_format.h"
 
34
#include "drizzled/temporal.h"
 
35
 
 
36
#include <string> /** C++ string class used */
 
37
#include <string.h>
 
38
#include <vector>
 
39
#include PCRE_HEADER
 
40
 
 
41
namespace drizzled
 
42
{
 
43
 
 
44
  TemporalFormat::TemporalFormat(const char *pattern)
 
45
  :
 
46
  _pattern(pattern)
 
47
, _error_offset(0)
 
48
, _error(NULL)
 
49
, _year_part_index(0)
 
50
, _month_part_index(0)
 
51
, _day_part_index(0)
 
52
, _hour_part_index(0)
 
53
, _minute_part_index(0)
 
54
, _second_part_index(0)
 
55
, _usecond_part_index(0)
 
56
, _nsecond_part_index(0)
 
57
{
 
58
  /* Make sure we've got no junk in the match_vector. */
 
59
  memset(_match_vector, 0, sizeof(_match_vector));
 
60
 
 
61
  /* Compile our regular expression */
 
62
  _re= pcre_compile(pattern
 
63
                    , 0 /* Default options */
 
64
                    , &_error
 
65
                    , &_error_offset
 
66
                    , NULL /* Use default character table */
 
67
                    );
 
68
}
 
69
 
 
70
bool TemporalFormat::matches(const char *data, size_t data_len, Temporal *to)
 
71
{
 
72
  if (! is_valid()) 
 
73
    return false;
 
74
  
 
75
  /* Simply check the subject against the compiled regular expression */
 
76
  int32_t result= pcre_exec(_re
 
77
                            , NULL /* No extra data */
 
78
                            , data
 
79
                            , data_len
 
80
                            , 0 /* Start at offset 0 of subject...*/
 
81
                            , 0 /* Default options */
 
82
                            , _match_vector
 
83
                            , OUT_VECTOR_SIZE
 
84
                            );
 
85
  if (result < 0)
 
86
  {
 
87
    switch (result)
 
88
    {
 
89
      case PCRE_ERROR_NOMATCH:
 
90
        return false; /* No match, just return false */
 
91
      default:
 
92
        return false;
 
93
    }
 
94
    return false;
 
95
  }
 
96
 
 
97
  int32_t expected_match_count= (_year_part_index > 1 ? 1 : 0)
 
98
                              + (_month_part_index > 1 ? 1 : 0)
 
99
                              + (_day_part_index > 1 ? 1 : 0)
 
100
                              + (_hour_part_index > 1 ? 1 : 0)
 
101
                              + (_minute_part_index > 1 ? 1 : 0)
 
102
                              + (_second_part_index > 1 ? 1 : 0)
 
103
                              + (_usecond_part_index > 1 ? 1 : 0)
 
104
                              + (_nsecond_part_index > 1 ? 1 : 0)
 
105
                              + 1; /* Add one for the entire match... */
 
106
  if (result != expected_match_count)
 
107
    return false;
 
108
 
 
109
  /* C++ string class easy to use substr() method is very useful here */
 
110
  std::string copy_data(data, data_len);
 
111
  /* 
 
112
   * OK, we have the expected substring matches, so grab
 
113
   * the various temporal parts from the subject string
 
114
   *
 
115
   * @note 
 
116
   *
 
117
   * TemporalFormatMatch is a friend class to Temporal, so
 
118
   * we can access the temporal instance's protected data.
 
119
   */
 
120
  if (_year_part_index > 1)
 
121
  {
 
122
    size_t year_start= _match_vector[_year_part_index];
 
123
    size_t year_len= _match_vector[_year_part_index + 1] - _match_vector[_year_part_index];
 
124
    to->_years= atoi(copy_data.substr(year_start, year_len).c_str());
 
125
    if (year_len == 2)
 
126
      to->_years+= (to->_years >= DRIZZLE_YY_PART_YEAR ? 1900 : 2000);
 
127
  }
 
128
  if (_month_part_index > 1)
 
129
  {
 
130
    size_t month_start= _match_vector[_month_part_index];
 
131
    size_t month_len= _match_vector[_month_part_index + 1] - _match_vector[_month_part_index];
 
132
    to->_months= atoi(copy_data.substr(month_start, month_len).c_str());
 
133
  }
 
134
  if (_day_part_index > 1)
 
135
  {
 
136
    size_t day_start= _match_vector[_day_part_index];
 
137
    size_t day_len= _match_vector[_day_part_index + 1] - _match_vector[_day_part_index];
 
138
    to->_days= atoi(copy_data.substr(day_start, day_len).c_str());
 
139
  }
 
140
  if (_hour_part_index > 1)
 
141
  {
 
142
    size_t hour_start= _match_vector[_hour_part_index];
 
143
    size_t hour_len= _match_vector[_hour_part_index + 1] - _match_vector[_hour_part_index];
 
144
    to->_hours= atoi(copy_data.substr(hour_start, hour_len).c_str());
 
145
  }
 
146
  if (_minute_part_index > 1)
 
147
  {
 
148
    size_t minute_start= _match_vector[_minute_part_index];
 
149
    size_t minute_len= _match_vector[_minute_part_index + 1] - _match_vector[_minute_part_index];
 
150
    to->_minutes= atoi(copy_data.substr(minute_start, minute_len).c_str());
 
151
  }
 
152
  if (_second_part_index > 1)
 
153
  {
 
154
    size_t second_start= _match_vector[_second_part_index];
 
155
    size_t second_len= _match_vector[_second_part_index + 1] - _match_vector[_second_part_index];
 
156
    to->_seconds= atoi(copy_data.substr(second_start, second_len).c_str());
 
157
  }
 
158
  if (_usecond_part_index > 1)
 
159
  {
 
160
    size_t usecond_start= _match_vector[_usecond_part_index];
 
161
    size_t usecond_len= _match_vector[_usecond_part_index + 1] - _match_vector[_usecond_part_index];
 
162
    /* 
 
163
     * For microseconds, which are millionth of 1 second, 
 
164
     * we must ensure that we produce a correct result, 
 
165
     * even if < 6 places were specified.  For instance, if we get .1, 
 
166
     * we must produce 100000. .11 should produce 110000, etc.
 
167
     */
 
168
    uint32_t multiplier= 1;
 
169
    int32_t x= usecond_len;
 
170
    while (x < 6)
 
171
    {
 
172
      multiplier*= 10;
 
173
      ++x;
 
174
    }
 
175
    to->_useconds= atoi(copy_data.substr(usecond_start, usecond_len).c_str()) * multiplier;
 
176
  }
 
177
  if (_nsecond_part_index > 1)
 
178
  {
 
179
    size_t nsecond_start= _match_vector[_nsecond_part_index];
 
180
    size_t nsecond_len= _match_vector[_nsecond_part_index + 1] - _match_vector[_nsecond_part_index];
 
181
    /* 
 
182
     * For nanoseconds, which are 1 billionth of a second, 
 
183
     * we must ensure that we produce a correct result, 
 
184
     * even if < 9 places were specified.  For instance, if we get .1, 
 
185
     * we must produce 100000000. .11 should produce 110000000, etc.
 
186
     */
 
187
    uint32_t multiplier= 1;
 
188
    int32_t x= nsecond_len;
 
189
    while (x < 9)
 
190
    {
 
191
      multiplier*= 10;
 
192
      ++x;
 
193
    }
 
194
    to->_nseconds= atoi(copy_data.substr(nsecond_start, nsecond_len).c_str()) * multiplier;
 
195
  }
 
196
  return true;
 
197
}
 
198
 
 
199
} /* end namespace drizzled */
 
200
 
 
201
#define COUNT_KNOWN_FORMATS 19
 
202
 
 
203
struct temporal_format_args
 
204
{
 
205
  const char *pattern;
 
206
  int32_t year_part_index;
 
207
  int32_t month_part_index;
 
208
  int32_t day_part_index;
 
209
  int32_t hour_part_index;
 
210
  int32_t minute_part_index;
 
211
  int32_t second_part_index;
 
212
  int32_t usecond_part_index;
 
213
  int32_t nsecond_part_index;
 
214
};
 
215
 
 
216
/**
 
217
 * A collection of all known format strings.
 
218
 *
 
219
 * @note
 
220
 *
 
221
 * IMPORTANT: Make sure TIMESTAMP and DATETIME formats precede DATE formats and TIME formats, 
 
222
 * as the matching functionality matches on the first hit.
 
223
 *
 
224
 * @note 
 
225
 *
 
226
 * Remember to increment COUNT_KNOWN_FORMATS when you add a known format!
 
227
 */
 
228
static struct temporal_format_args __format_args[COUNT_KNOWN_FORMATS]= 
 
229
{
 
230
  {"^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})\\.(\\d{1,6})$", 1, 2, 3, 4, 5, 6, 7, 0} /* YYYYMMDDHHmmSS.uuuuuu */
 
231
, {"^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})$", 1, 2, 3, 4, 5, 6, 0, 0} /* YYYYMMDDHHmmSS */
 
232
, {"^(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})[T|\\s+](\\d{2}):(\\d{2}):(\\d{2})\\.(\\d{1,6})$", 1, 2, 3, 4, 5, 6, 7, 0} /* YYYY[/-.]MM[/-.]DD[T]HH:mm:SS.uuuuuu */
 
233
, {"^(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})[T|\\s+](\\d{2}):(\\d{2}):(\\d{2})$", 1, 2, 3, 4, 5, 6, 0, 0} /* YYYY[/-.][M]M[/-.][D]D[T]HH:mm:SS */
 
234
, {"^(\\d{2})[-/.](\\d{1,2})[-/.](\\d{1,2})[\\s+](\\d{2}):(\\d{2}):(\\d{2})$", 1, 2, 3, 4, 5, 6, 0, 0} /* YY[/-.][M]M[/-.][D]D HH:mm:SS */
 
235
, {"^(\\d{2})[-/.](\\d{1,2})[-/.](\\d{1,2})[\\s+](\\d{2}):(\\d{2})$", 1, 2, 3, 4, 5, 0, 0, 0} /* YY[/-.][M]M[/-.][D]D HH:mm */
 
236
, {"^(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})[\\s+](\\d{2}):(\\d{2})$", 1, 2, 3, 4, 5, 0, 0, 0} /* YYYY[/-.][M]M[/-.][D]D HH:mm */
 
237
, {"^(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YYYY-[M]M-[D]D, YYYY.[M]M.[D]D, YYYY/[M]M/[D]D */
 
238
, {"^(\\d{4})(\\d{2})(\\d{2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YYYYMMDD */
 
239
, {"^(\\d{2})[-/.]*(\\d{2})[-/.]*(\\d{4})$", 3, 1, 2, 0, 0, 0, 0, 0} /* MM[-/.]DD[-/.]YYYY (US common format)*/
 
240
, {"^(\\d{2})[-/.]*(\\d{2})[-/.]*(\\d{2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YY[-/.]MM[-/.]DD */
 
241
, {"^(\\d{2})[-/.]*(\\d{1,2})[-/.]*(\\d{1,2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YY[-/.][M]M[-/.][D]D */
 
242
, {"^(\\d{4})[-/.]*(\\d{1,2})[-/.]*(\\d{1,2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YYYY[-/.][M]M[-/.][D]D */
 
243
, {"^(\\d{2}):*(\\d{2}):*(\\d{2})\\.(\\d{1,6})$", 0, 0, 0, 1, 2, 3, 4, 0} /* HHmmSS.uuuuuu, HH:mm:SS.uuuuuu */
 
244
, {"^(\\d{1,2}):*(\\d{2}):*(\\d{2})$", 0, 0, 0, 1, 2, 3, 0, 0} /* [H]HmmSS, [H]H:mm:SS */
 
245
, {"^(\\d{1,2}):(\\d{1,2}):(\\d{1,2})$", 0, 0, 0, 1, 2, 3, 0, 0} /* [H]H:[m]m:[S]S */
 
246
, {"^(\\d{1,2}):*(\\d{2})$", 0, 0, 0, 0, 1, 2, 0, 0} /* [m]mSS, [m]m:SS */
 
247
, {"^(\\d{1,2})$", 0, 0, 0, 0, 0, 1, 0, 0} /* SS, S */
 
248
, {"^(\\d{1,2})\\.(\\d{1,6})$", 0, 0, 0, 0, 0, 1, 2, 0} /* [S]S.uuuuuu */
 
249
};
 
250
 
 
251
std::vector<drizzled::TemporalFormat *> known_datetime_formats;
 
252
std::vector<drizzled::TemporalFormat *> known_date_formats;
 
253
std::vector<drizzled::TemporalFormat *> known_time_formats;
 
254
std::vector<drizzled::TemporalFormat *> all_temporal_formats;
 
255
 
 
256
/**
 
257
 * We allocate and initialize all known date/time formats.
 
258
 *
 
259
 * @TODO Cut down calls to new. Allocate as a block...
 
260
 */
 
261
bool init_temporal_formats()
 
262
{
 
263
  /* Compile all the regular expressions for the datetime formats */
 
264
  drizzled::TemporalFormat *tmp;
 
265
  struct temporal_format_args current_format_args;
 
266
  int32_t x;
 
267
  
 
268
  for (x= 0; x<COUNT_KNOWN_FORMATS; ++x)
 
269
  {
 
270
    current_format_args= __format_args[x];
 
271
    tmp= new drizzled::TemporalFormat(current_format_args.pattern);
 
272
    tmp->set_year_part_index(current_format_args.year_part_index);
 
273
    tmp->set_month_part_index(current_format_args.month_part_index);
 
274
    tmp->set_day_part_index(current_format_args.day_part_index);
 
275
    tmp->set_hour_part_index(current_format_args.hour_part_index);
 
276
    tmp->set_minute_part_index(current_format_args.minute_part_index);
 
277
    tmp->set_second_part_index(current_format_args.second_part_index);
 
278
    tmp->set_usecond_part_index(current_format_args.usecond_part_index);
 
279
    tmp->set_nsecond_part_index(current_format_args.nsecond_part_index);
 
280
    
 
281
    /* 
 
282
     * We store the pointer in all_temporal_formats because we 
 
283
     * delete pointers from that vector and only that vector
 
284
     */
 
285
    all_temporal_formats.push_back(tmp); 
 
286
 
 
287
    if (current_format_args.year_part_index > 0) /* A date must have a year */
 
288
    {
 
289
      known_datetime_formats.push_back(tmp);
 
290
      if (current_format_args.second_part_index == 0) /* A time must have seconds. */
 
291
        known_date_formats.push_back(tmp);
 
292
    }
 
293
    if (current_format_args.second_part_index > 0) /* A time must have seconds, but may not have minutes or hours */
 
294
      if (current_format_args.year_part_index == 0) /* A time may not have a date part, and date parts must have a year */
 
295
        known_time_formats.push_back(tmp);
 
296
  }
 
297
  return true;
 
298
}
 
299
 
 
300
/** Free all allocated temporal formats */
 
301
void deinit_temporal_formats()
 
302
{
 
303
  std::vector<drizzled::TemporalFormat *>::iterator p= all_temporal_formats.begin();
 
304
  while (p != all_temporal_formats.end())
 
305
  {
 
306
    delete *p;
 
307
    ++p;
 
308
  }
 
309
  known_date_formats.clear();
 
310
  known_datetime_formats.clear();
 
311
  known_time_formats.clear();
 
312
  all_temporal_formats.clear();
 
313
}